暖棕萌粉的宠物经济视觉语言:HarmonyOS ArkUI 萌宠家服务平台组件化架构全解析
一、技术前言
随着宠物经济在中国市场的持续爆发式增长,宠物服务类应用已从简单的信息展示工具进化为涵盖医疗、美容、寄养、社交、电商等多维度的综合服务平台。根据行业白皮书数据,2025 年中国宠物市场规模突破 8000 亿元,其中线上服务预约占比超过 35%。这一趋势对移动端应用提出了更高的要求:不仅需要在有限的屏幕空间内承载多种业务形态,还要在视觉上传递温暖、可信赖的品牌感受。





鸿蒙 HarmonyOS 的 ArkUI 框架为这类需求提供了理想的声明式 UI 开发范式。与传统的命令式 UI 不同,ArkUI 采用 @Component + @Builder 的组件化拆分策略,通过状态驱动视图更新,开发者只需关注数据变化,框架自动完成 UI 的差异渲染。这一机制极大简化了多 Tab 页面、弹窗交互、动画效果等复杂场景的实现。
在本篇中,我们将深入剖析一个宠物服务平台的完整 ArkUI 实现方案。该应用覆盖六个核心业务场景——首页推荐、附近商家、订单管理、宠物档案、社区动态和个人中心——每个场景采用差异化的布局策略,避免视觉重复。技术上采用了以下关键决策:
- @Observed + @State 双层状态管理:数据模型使用
@Observed装饰器实现可观察性,组件内通过@State持有状态引用,数据变化自动触发局部刷新 - 预计算常量数组替代运行时 filter:规避 ArkUI 中
filter回调导致的不必要重渲染风险 - 单定时器呼吸动画:全局仅一处
setInterval,通过布尔翻转驱动一个透明度动画循环,避免多重定时器的性能开销 - Builder 函数组件化拆分:13 个
@Builder函数将 1200+ 行的组件拆解为可维护的独立模块 - 状态颜色映射工具函数:将业务状态(待支付/进行中/已完成等)与视觉色彩解耦,集中管理颜色策略
二、整体架构流程图
从架构图可以看出,整个应用采用四层架构:入口层负责生命周期管理,组件层负责状态持有和布局编排,Builder 层负责各区域的视觉渲染,数据层负责业务数据的封装与传递。常量和工具函数作为横切关注点,被各层按需引用。
三、色彩体系设计
3.1 ColorPalette 接口定义
应用首先定义了一个 ColorPalette 接口,作为整个色彩体系的类型契约:
interface ColorPalette {
bg: string; // 页面背景
cardBg: string; // 卡片背景
textPrimary: string; // 主文字
textSecondary: string;// 次文字
textTertiary: string; // 三级文字
accent: string; // 强调色
accentLight: string; // 浅强调色
warm: string; // 暖色
warmLight: string; // 浅暖色
border: string; // 边框色
success: string; // 成功状态
warning: string; // 警告状态
danger: string; // 危险状态
info: string; // 信息状态
gradientStart: string;// 渐变起始
gradientEnd: string; // 渐变结束
divider: string; // 分割线
overlay: string; // 遮罩层
}
这一接口定义了 18 个色彩字段,覆盖了从背景到前景、从文字到状态、从渐变到遮罩的全场景需求。接口的作用不仅在于类型约束,更重要的是建立了色彩使用的语义化命名体系——开发者通过字段名即可理解色彩的用途,无需记忆具体的十六进制值。
3.2 COLORS 常量逐色分析
const COLORS: ColorPalette = {
bg: '#FAF5F0', // 暖米色背景
cardBg: '#FFFFFF', // 纯白卡片
textPrimary: '#3D2E1F', // 深棕主文字
textSecondary: '#8B7355', // 暖灰次文字
textTertiary: '#BFA88E', // 浅棕三级文字
accent: '#E67E22', // 活力橙强调
accentLight: '#FFE4B5', // 浅橙背景
warm: '#D4A574', // 温暖棕
warmLight: '#F5DEB3', // 浅暖色
border: '#E8DCC9', // 暖灰边框
success: '#4CAF50', // 标准绿
warning: '#FF9800', // 标准橙
danger: '#F44336', // 标准红
info: '#2196F3', // 标准蓝
gradientStart: '#E67E22', // 渐变起点橙
gradientEnd: '#D4A574', // 渐变终点棕
divider: '#F0E6D2', // 浅暖分割线
overlay: '#00000066' // 半透明遮罩
};
对上述色彩进行分类解读:
背景层:bg: #FAF5F0 是一个偏暖的米色调白色,比纯白 #FFFFFF 多了一份柔和感,营造宠物店的温馨氛围。cardBg 保持纯白以确保卡片内容在暖色背景上的清晰度,形成"暖底白卡"的层次对比。
文字层:三级文字色从 #3D2E1F(深棕)到 #8B7355(暖灰)再到 #BFA88E(浅棕),全部采用棕色系而非纯黑纯灰,与整体暖色调保持一致。这种设计避免了文字色与环境色的割裂感。
强调色:accent: #E67E22 是品牌核心色——活力橙,用于按钮、图标、选中态等关键交互元素。accentLight: #FFE4B5 作为强调色的浅色变体,用于背景填充和标签底色。
渐变系:gradientStart 到 gradientEnd 从橙色过渡到棕色,用于头部区域的线性渐变,模拟日落色调,呼应"回家"的情感隐喻。
状态色:成功、警告、危险、信息四个状态色采用业界通用的绿/橙/红/蓝标准色,确保用户在跨应用使用时的认知一致性,不因品牌色而牺牲可辨识度。
四、Tab 元数据与辅助数据
4.1 Tab 元数据定义
const TAB_LIST = [
{ icon: $r('app.media.ic_public_0'), label: '首页' },
{ icon: $r('app.media.ic_public_1'), label: '附近' },
{ icon: $r('app.media.ic_public_2'), label: '订单' },
{ icon: $r('app.media.ic_public_3'), label: '档案' },
{ icon: $r('app.media.ic_public_4'), label: '社区' },
{ icon: $r('app.media.ic_public_5'), label: '我的' }
] as const;
TAB_LIST 使用 as const 断言确保类型为只读元组,防止运行时意外修改。每个 Tab 包含图标资源和标签文字两个字段。六个 Tab 覆盖了宠物服务的完整用户路径:从浏览推荐(首页)到线下消费(附近),从交易记录(订单)到信息管理(档案),从社交互动(社区)到个人中心(我的)。
4.2 图表数据
const CHART_DATA = [
{ label: '1月', value: 3200 },
{ label: '2月', value: 2800 },
{ label: '3月', value: 4500 },
{ label: '4月', value: 3800 },
{ label: '5月', value: 5200 },
{ label: '6月', value: 4800 }
] as const;
图表数据模拟了半年的消费统计,数值在 2800~5200 区间波动,符合宠物消费的季节性特征——5 月达到峰值(可能对应春季宠物美容高峰),2 月为低谷(春节后消费紧缩)。数据使用 as const 冻结为只读,确保渲染过程中不被篡改。
4.3 分类标签
const CATEGORY_LABELS = ['全部', '医疗', '美容', '寄养', '训练', '社交'] as const;
六个分类标签覆盖了宠物服务的主要业务类别,"全部"作为默认筛选态放在首位。这些标签在社区 Tab 中用于内容分类过滤。
五、工具函数
5.1 订单状态颜色映射
function orderStatusColor(status: string): string {
const map: Record<string, string> = {
'待支付': COLORS.warning,
'进行中': COLORS.info,
'已完成': COLORS.success,
'已取消': COLORS.danger
};
return map[status] ?? COLORS.textTertiary;
}
该函数实现了订单状态到视觉颜色的映射策略。使用 Record<string, string> 类型定义确保映射表的类型安全,四个状态分别对应警告(橙)、信息(蓝)、成功(绿)、危险(红)四色。?? COLORS.textTertiary 作为空值合并兜底,当传入未定义的状态时回退到三级文字色,避免颜色为 undefined 导致渲染异常。
5.2 任务颜色映射
function taskColor(priority: string): string {
const map: Record<string, string> = {
'高': COLORS.danger,
'中': COLORS.warning,
'低': COLORS.success
};
return map[priority] ?? COLORS.textSecondary;
}
任务优先级颜色映射采用同样的策略,高/中/低分别映射为红/橙/绿,符合用户对优先级的直觉认知。兜底色为次文字色 #8B7355,在视觉上弱于三种状态色但不会消失。
两个工具函数的核心设计思想是将颜色策略与业务逻辑解耦。如果未来需要调整颜色方案(例如暗色模式适配),只需修改 COLORS 常量或映射表,无需改动各 Builder 函数中的颜色引用。
六、数据模型层
应用定义了 6 个 @Observed 数据模型类,每个类对应一个核心业务实体。
6.1 PetService 服务模型
@Observed
class PetService {
title: string = '';
desc: string = '';
price: number = 0;
icon: string = '🐾';
tag: string = '';
rating: number = 0;
}
PetService 描述宠物服务项目(如体检、洗浴等),包含标题、描述、价格、图标 emoji、标签和评分六个字段。@Observed 装饰器使该类的实例在被 @State 引用时自动具备观察性——任何属性变化都会触发引用了该实例的 UI 组件重新渲染。icon 字段使用 emoji 字符串而非图片资源,是一种轻量化的图标方案,适合快速原型和内容频繁变化的场景。
6.2 PetShop 商家模型
@Observed
class PetShop {
name: string = '';
type: string = '';
distance: string = '';
rating: number = 0;
tags: string[] = [];
}
PetShop 描述周边商家信息,tags 字段为字符串数组,用于存储商家的特色标签(如"24小时"、"免费停车"等)。数组类型在 ArkUI 中可以配合 ForEach 直接渲染列表项。
6.3 PetOrder 订单模型
@Observed
class PetOrder {
service: string = '';
shop: string = '';
date: string = '';
price: number = 0;
status: string = '';
}
PetOrder 记录用户的消费订单,status 字段的值(待支付/进行中/已完成/已取消)通过前述 orderStatusColor 函数映射为视觉颜色,实现数据与展示的分离。
6.4 PetProfile 档案模型
@Observed
class PetProfile {
name: string = '';
breed: string = '';
age: string = '';
weight: string = '';
vaccine: string = '';
lastCheck: string = '';
}
PetProfile 存储宠物的基本档案信息,包括名字、品种、年龄、体重、疫苗记录和上次体检日期。六个字段覆盖了宠物健康管理的核心信息维度。
6.5 PetPost 社区动态模型
@Observed
class PetPost {
author: string = '';
avatar: string = '';
content: string = '';
likes: number = 0;
comments: number = 0;
category: string = '';
}
PetPost 描述社区互动内容,包含作者信息、内容正文、点赞数、评论数和分类标签。avatar 使用 emoji 字符串,与 PetService 的 icon 设计保持一致。
6.6 PetTask 任务模型
@Observed
class PetTask {
title: string = '';
time: string = '';
priority: string = '';
done: boolean = false;
}
PetTask 是个人中心的待办任务项,done 布尔字段控制任务完成状态,priority 字段通过 taskColor 函数映射为颜色。
所有 6 个模型类均使用 @Observed 装饰器,字段均提供默认值(= '' 或 = 0),确保构造函数可以无参实例化。这一设计简化了 Mock 数据的创建——先 new PetService() 再逐属性赋值,避免构造函数参数列表过长。
七、组件主体结构
7.1 @State 状态变量组
@Entry
@Component
struct Index {
@State currentTab: number = 0;
@State services: PetService[] = [/* 6 条 Mock 数据 */];
@State shops: PetShop[] = [/* 6 条 Mock 数据 */];
@State orders: PetOrder[] = [/* 6 条 Mock 数据 */];
@State profiles: PetProfile[] = [/* 3 条 Mock 数据 */];
@State posts: PetPost[] = [/* 6 条 Mock 数据 */];
@State tasks: PetTask[] = [/* 6 条 Mock 数据 */];
@State showModal: boolean = false;
@State modalType: string = 'add';
@State editTarget: PetService | PetShop | PetOrder | PetProfile | PetPost | PetTask | null = null;
@State breathFlag: boolean = false;
@State scrollY: number = 0;
@State selectedCategory: number = 0;
@State activeTabLabel: string = '首页';
}
组件持有 14 个 @State 变量,可分为四类:
页面导航状态:currentTab(当前 Tab 索引)、activeTabLabel(当前 Tab 名称)、selectedCategory(社区分类选中索引),控制页面导航和筛选状态。
业务数据集合:六个 @Observed 类的数组,分别对应六个 Tab 的数据源。数组引用变化时(如增删元素),ArkUI 自动触发对应区域的重新渲染。
弹窗交互状态:showModal(弹窗显隐)、modalType(弹窗类型:add/edit/delete)、editTarget(编辑目标对象,使用联合类型支持所有模型),三个变量协作控制弹窗系统的行为。
动画与滚动状态:breathFlag(呼吸动画布尔翻转标志)、scrollY(滚动位置),前者驱动呼吸动画循环,后者记录内容区滚动偏移。
7.2 呼吸动画生命周期
aboutToAppear() {
setInterval(() => {
this.breathFlag = !this.breathFlag;
}, 1800);
}
组件生命周期 aboutToAppear 在组件创建后、渲染前触发。此处注册一个间隔 1800 毫秒的定时器,每次执行时翻转 breathFlag 布尔值。由于 breathFlag 是 @State 变量,其值变化会自动触发引用了该变量的 UI 区域重新渲染——即头部 Logo 的透明度动画。1800 毫秒的间隔恰好匹配一次"呼吸"周期(吸气 + 呼气),营造出 Logo 轻微脉动的视觉效果。
这种设计的优势在于单定时器驱动单状态,整个应用只有一处 setInterval,避免了多个定时器叠加导致的性能开销和内存泄漏风险。
7.3 build() 主布局
build() {
Column() {
this.headerHome()
Scroll() {
Column() {
if (this.currentTab === 0) {
this.tabHome()
} else if (this.currentTab === 1) {
this.tabNearby()
} else if (this.currentTab === 2) {
this.tabOrders()
} else if (this.currentTab === 3) {
this.tabProfile()
} else if (this.currentTab === 4) {
this.tabCommunity()
} else if (this.currentTab === 5) {
this.tabMine()
}
}
}
.scrollBar(BarState.Off)
.layoutWeight(1)
this.tabBar()
this.modalOverlay()
}
.backgroundColor(COLORS.bg)
.height('100%')
}
build() 方法是组件的渲染入口,采用 Column 作为根容器,自上而下排列三个区域:headerHome()(固定头部)、Scroll + Column(可滚动内容区)、tabBar()(固定底部栏),外加 modalOverlay()(弹窗遮罩层,默认隐藏)。
内容区使用 if-else if 条件渲染根据 currentTab 值切换六个 Tab 的 Builder 函数。ArkUI 的条件渲染会创建/销毁组件实例,确保同一时刻只有当前 Tab 的组件存在于渲染树中,节省内存。
.scrollBar(BarState.Off) 隐藏滚动条,.layoutWeight(1) 让内容区占据头部和底部栏之间的全部剩余空间。根容器设置 .height('100%') 确保填满屏幕。
八、头部区域详解
@Builder
headerHome() {
Stack({ alignContent: Alignment.Center }) {
// 渐变背景层
Column()
.width('100%')
.height(56)
.linearGradient({
direction: GradientDirection.Right,
colors: [[COLORS.gradientStart, 0], [COLORS.gradientEnd, 1]]
})
// 内容层:Logo + 标题 + 通知按钮
Row() {
Text('🐾')
.fontSize(24)
.opacity(this.breathFlag ? 0.7 : 1.0)
.animation({
duration: 1500,
curve: Curve.EaseInOut
})
Text('萌宠家')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
.margin({ left: 8 })
Blank()
Text('🔔')
.fontSize(20)
}
.width('90%')
.height(56)
.justifyContent(FlexAlign.Start)
}
.width('100%')
.height(56)
}
头部区域使用 Stack 叠加布局,底层是 56vp 高的渐变色背景,上层是水平排列的内容行。
渐变背景:使用 linearGradient 从左到右(GradientDirection.Right)渲染,起点色 #E67E22(活力橙)到终点色 #D4A574(温暖棕),模拟日落的色彩过渡。0 到 1 的颜色锚点确保渐变从最左到最右完整覆盖。
Logo 呼吸动画:🐾 emoji 的 opacity 绑定到 breathFlag 状态——当 breathFlag 为 true 时透明度降至 0.7,为 false 时恢复 1.0。配合 .animation({ duration: 1500, curve: Curve.EaseInOut }),ArkUI 会在 1500 毫秒内以缓入缓出曲线完成透明度过渡。由于定时器每 1800 毫秒翻转一次,实际效果是 Logo 在 1.5 秒内缓慢变暗,然后在下一个 1.5 秒缓慢变亮,形成"呼吸"节奏。
Blank() 组件占据中间所有剩余空间,将通知按钮 🔔 推到右侧。Row 宽度设为 90%,在 Stack 居中后左右各留 5% 边距。
九、首页 Tab 分析(tabHome)
首页采用双列卡片网格布局,展示推荐服务。
@Builder
tabHome() {
Column() {
// 搜索框
Row() {
Text('🔍')
.fontSize(16)
Text('搜索宠物服务...')
.fontSize(14)
.fontColor(COLORS.textTertiary)
.margin({ left: 8 })
Blank()
Text('📷')
.fontSize(16)
}
.width('92%')
.height(40)
.backgroundColor(COLORS.cardBg)
.borderRadius(20)
.padding({ left: 16, right: 16 })
.margin({ top: 12, bottom: 12 })
// 双列卡片网格
Row() {
ForEach(this.services.slice(0, 4), (s: PetService) => {
Column() {
Text(s.icon).fontSize(32)
Text(s.title)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ top: 8 })
Text(s.desc)
.fontSize(12)
.fontColor(COLORS.textSecondary)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.margin({ top: 4 })
Text(`¥${s.price}`)
.fontSize(16)
.fontColor(COLORS.accent)
.fontWeight(FontWeight.Bold)
.margin({ top: 8 })
}
.layoutWeight(1)
.backgroundColor(COLORS.cardBg)
.borderRadius(12)
.padding(12)
.margin({ right: 4, bottom: 8 })
}, (s: PetService) => s.title)
}
.width('92%')
// 下方两个卡片
Row() {
ForEach(this.services.slice(4, 6), (s: PetService) => {
// ... 同上卡片结构
})
}
.width('92%')
.margin({ bottom: 16 })
}
.width('100%')
}
首页的核心布局策略是 2×3 卡片网格,通过两次 Row + ForEach 实现,每次取 services 数组的 2 个元素。每个卡片使用 Column 垂直排列 emoji 图标、标题、描述和价格四层信息。
.slice(0, 4) 和 .slice(4, 6) 将 6 条数据分为两批渲染,而非使用一个 ForEach 渲染 6 个卡片。这种"分批 ForEach"策略确保了两行卡片的布局精确性——每行严格 2 个卡片,各占 layoutWeight(1) 等分宽度。
文本溢出处理是首页的重要细节:.maxLines(1) 限制描述文字为单行,.textOverflow({ overflow: TextOverflow.Ellipsis }) 在溢出时显示省略号。这一组合确保了卡片高度在内容长短不一时保持一致,避免因某个描述过长导致整行卡片高度不齐。
十、附近 Tab 分析(tabNearby)
附近 Tab 采用列表卡片布局,每张卡片包含商家名称、类型、距离、评分和标签。
@Builder
tabNearby() {
Column() {
ForEach(this.shops, (shop: PetShop) => {
Row() {
// 左侧:商家图标占位
Column() {
Text('🏪').fontSize(28)
}
.width(56)
.height(56)
.backgroundColor(COLORS.warmLight)
.borderRadius(12)
.justifyContent(FlexAlign.Center)
// 右侧:信息区
Column() {
Row() {
Text(shop.name)
.fontSize(15)
.fontWeight(FontWeight.Medium)
Blank()
Text(shop.distance)
.fontSize(12)
.fontColor(COLORS.accent)
}
.width('100%')
Row() {
Text(shop.type)
.fontSize(12)
.fontColor(COLORS.textSecondary)
Text('⭐'.repeat(Math.ceil(shop.rating)))
.fontSize(10)
.margin({ left: 8 })
Blank()
Text(`${shop.rating}`)
.fontSize(12)
.fontColor(COLORS.warning)
}
.width('100%')
.margin({ top: 4 })
// 标签行
Row() {
ForEach(shop.tags, (tag: string) => {
Text(tag)
.fontSize(10)
.fontColor(COLORS.warm)
.backgroundColor(COLORS.warmLight)
.borderRadius(4)
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.margin({ right: 6 })
}, (tag: string) => tag)
}
.margin({ top: 6 })
}
.layoutWeight(1)
.margin({ left: 12 })
.alignItems(VerticalAlign.Top)
}
.width('92%')
.backgroundColor(COLORS.cardBg)
.borderRadius(12)
.padding(12)
.margin({ bottom: 8 })
}, (shop: PetShop) => shop.name)
}
.width('100%')
.padding({ top: 12 })
}
与首页的双列网格不同,附近 Tab 采用水平分栏卡片布局:左侧 56vp 的圆角图标区(暖色背景 + emoji),右侧 layoutWeight(1) 的信息区。信息区内部分为三行——名称行(含距离)、类型评分行(含星级和评分数字)、标签行。
星级渲染使用 '⭐'.repeat(Math.ceil(shop.rating)),将评分数字转换为对应数量的 emoji 星星。Math.ceil 确保评分为 4.5 时显示 5 颗星,是一种向上取整的评分展示策略。
标签行使用嵌套的 ForEach 遍历 shop.tags 数组,每个标签用浅暖色背景 + 暖色文字渲染,形成"药丸"形态的标签。
.alignItems(VerticalAlign.Top) 确保右侧信息区顶部对齐左侧图标区,避免因信息行数不同导致内容垂直居中时的错位。
十一、订单 Tab 分析(tabOrders)
订单 Tab 采用时间轴样式布局,通过左侧的状态色条和连线模拟时间轴效果。
@Builder
tabOrders() {
Column() {
ForEach(this.orders, (order: PetOrder, idx: number) => {
Row() {
// 左侧色条 + 时间轴效果
Column() {
// 顶部连线(第一个订单不显示)
if (idx > 0) {
Line()
.width(2)
.height(20)
.color(COLORS.divider)
}
// 状态圆点
Circle({ width: 10, height: 10 })
.fill(orderStatusColor(order.status))
// 底部连线(最后一个订单不显示)
if (idx < this.orders.length - 1) {
Line()
.width(2)
.height(40)
.color(COLORS.divider)
}
}
.width(24)
.alignItems(HorizontalAlign.Center)
// 右侧订单卡片
Column() {
Row() {
Text(order.service)
.fontSize(14)
.fontWeight(FontWeight.Medium)
Blank()
Text(`¥${order.price}`)
.fontSize(14)
.fontColor(COLORS.accent)
.fontWeight(FontWeight.Bold)
}
Row() {
Text(order.shop)
.fontSize(12)
.fontColor(COLORS.textSecondary)
Blank()
Text(order.date)
.fontSize(11)
.fontColor(COLORS.textTertiary)
}
.margin({ top: 4 })
Row() {
Text(order.status)
.fontSize(11)
.fontColor(orderStatusColor(order.status))
.backgroundColor(orderStatusColor(order.status).replace('#', '#').slice(0, 7) + '15')
.borderRadius(4)
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
}
.margin({ top: 6 })
}
.layoutWeight(1)
.backgroundColor(COLORS.cardBg)
.borderRadius(12)
.padding(12)
.margin({ left: 8 })
}
.width('92%')
.margin({ bottom: 4 })
}, (order: PetOrder) => `${order.service}_${idx}`)
}
.width('100%')
.padding({ top: 12 })
}
订单 Tab 的核心视觉创新是左侧时间轴。每个订单项的左侧 Column 包含三部分:顶部连线(Line 组件,2vp 宽,20vp 高,浅色)、状态圆点(Circle 组件,10vp 直径,填充状态颜色)、底部连线(40vp 高的 Line)。首项不显示顶部连线,末项不显示底部连线,形成连贯的时间轴视觉效果。
状态圆点颜色由 orderStatusColor 函数动态计算——待支付为橙色、进行中为蓝色、已完成为绿色、已取消为红色,用户一眼即可区分订单状态分布。
状态标签的背景色使用了巧妙的颜色操作:orderStatusColor(order.status) 返回的十六进制色值拼接 '15' 后缀,形成低透明度的同色背景。例如 #FF9800 + 15 = #FF980015,即 8% 透明度的橙色背景。这种设计确保标签背景与文字颜色同源,视觉上自然协调。
ForEach 的 key 使用了 `${order.service}_${idx}` 模板字符串,将服务名与索引组合作为唯一键。这是因为可能存在同名服务(如两次洗浴),纯名称作 key 会冲突,加索引保证唯一性。
十二、档案 Tab 分析(tabProfile)
档案 Tab 展示宠物基本信息,采用大卡片布局。
@Builder
tabProfile() {
Column() {
ForEach(this.profiles, (p: PetProfile) => {
Column() {
// 头部:头像 + 名字 + 品种
Row() {
Column() {
Text('🐕').fontSize(40)
}
.width(64)
.height(64)
.backgroundColor(COLORS.warmLight)
.borderRadius(32)
.justifyContent(FlexAlign.Center)
Column() {
Text(p.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
Text(p.breed)
.fontSize(12)
.fontColor(COLORS.textSecondary)
.margin({ top: 2 })
}
.margin({ left: 12 })
.alignItems(VerticalAlign.Top)
Blank()
Text('编辑')
.fontSize(12)
.fontColor(COLORS.accent)
.onClick(() => {
this.modalType = 'edit';
this.editTarget = p;
this.showModal = true;
})
}
// 分割线
Divider()
.color(COLORS.divider)
.margin({ top: 12, bottom: 12 })
// 信息网格:年龄 / 体重 / 疫苗 / 上次体检
Row() {
Column() {
Text('年龄')
.fontSize(11)
.fontColor(COLORS.textTertiary)
Text(p.age)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ top: 4 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
Column() {
Text('体重')
.fontSize(11)
.fontColor(COLORS.textTertiary)
Text(p.weight)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ top: 4 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
Column() {
Text('疫苗')
.fontSize(11)
.fontColor(COLORS.textTertiary)
Text(p.vaccine)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ top: 4 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
Column() {
Text('上次体检')
.fontSize(11)
.fontColor(COLORS.textTertiary)
Text(p.lastCheck)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ top: 4 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
}
}
.width('92%')
.backgroundColor(COLORS.cardBg)
.borderRadius(16)
.padding(16)
.margin({ bottom: 12 })
}, (p: PetProfile) => p.name)
}
.width('100%')
.padding({ top: 12 })
}
档案 Tab 的布局特色在于四宫格信息区。在头像和名字的头部行之后,通过 Divider 组件绘制水平分割线,然后使用 Row + 4 个等宽 Column(各 layoutWeight(1))构建四宫格信息区:年龄、体重、疫苗、上次体检。每个格子上下排列标签(11vp 浅棕色)和数值(14vp 中等粗细),居中对齐。
"编辑"按钮的点击事件是一个典型的状态驱动弹窗交互:设置 modalType 为 'edit',editTarget 为当前 PetProfile 实例,showModal 为 true。三个 @State 变量的变化会同步触发弹窗组件的显示和内容填充,无需命令式的 DOM 操作。
头像区域使用 64vp × 64vp 的圆形背景(borderRadius(32) 实现圆形),填充暖色,内置 emoji 宠物图标。justifyContent(FlexAlign.Center) 确保 emoji 在圆形容器内居中。
十三、社区 Tab 分析(tabCommunity)
社区 Tab 包含分类筛选条和信息流列表。
@Builder
tabCommunity() {
Column() {
// 分类筛选条
Scroll() {
Row() {
ForEach(CATEGORY_LABELS, (label: string, idx: number) => {
Text(label)
.fontSize(13)
.fontColor(this.selectedCategory === idx ? '#FFFFFF' : COLORS.textSecondary)
.backgroundColor(this.selectedCategory === idx ? COLORS.accent : COLORS.accentLight)
.borderRadius(16)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.margin({ right: 8 })
.onClick(() => {
this.selectedCategory = idx;
})
}, (label: string) => label)
}
.padding({ left: 12, right: 12 })
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
.height(44)
// 动态列表
ForEach(this.posts, (post: PetPost) => {
Column() {
// 作者行
Row() {
Text(post.avatar).fontSize(28)
Column() {
Text(post.author)
.fontSize(13)
.fontWeight(FontWeight.Medium)
Text(post.category)
.fontSize(11)
.fontColor(COLORS.textTertiary)
.margin({ top: 2 })
}
.margin({ left: 8 })
.alignItems(VerticalAlign.Top)
Blank()
Text('关注')
.fontSize(11)
.fontColor(COLORS.accent)
}
.width('100%')
// 内容
Text(post.content)
.fontSize(14)
.fontColor(COLORS.textPrimary)
.margin({ top: 8 })
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
// 互动行
Row() {
Text(`❤️ ${post.likes}`).fontSize(12).fontColor(COLORS.textSecondary)
Text(`💬 ${post.comments}`).fontSize(12).fontColor(COLORS.textSecondary).margin({ left: 16 })
Blank()
Text('🗑️').fontSize(12)
.onClick(() => {
this.modalType = 'delete';
this.editTarget = post;
this.showModal = true;
})
}
.width('100%')
.margin({ top: 8 })
}
.width('92%')
.backgroundColor(COLORS.cardBg)
.borderRadius(12)
.padding(12)
.margin({ bottom: 8 })
}, (post: PetPost) => post.content)
}
.width('100%')
}
社区 Tab 的核心交互是水平滚动的分类筛选条。分类标签横向排列在 Scroll 容器中(scrollable(ScrollDirection.Horizontal)),当前选中项使用橙底白字,未选中项使用浅橙底暖灰字,形成鲜明的选中态对比。点击分类时仅更新 selectedCategory 索引值,ArkUI 自动重新渲染筛选条样式。
信息流卡片包含三层信息:作者行(emoji 头像 + 名字 + 分类 + 关注按钮)、内容正文(限制 2 行 + 省略号)、互动行(点赞数 + 评论数 + 删除按钮)。删除按钮通过 .onClick 设置弹窗交互,与档案 Tab 的编辑按钮使用相同的状态驱动模式。
分类筛选条的宽度设为 44vp 固定高度,内部 Row 的 padding 确保标签不贴边。.scrollBar(BarState.Off) 隐藏水平滚动条,保持视觉简洁。
十四、我的 Tab 分析(tabMine)
我的 Tab 是结构最复杂的页面,分为三大区块:用户卡片、消费统计图表和任务清单。
@Builder
tabMine() {
Column() {
// 区块一:用户信息卡片
Row() {
Column() {
Text('👤').fontSize(36)
}
.width(72)
.height(72)
.backgroundColor(COLORS.accentLight)
.borderRadius(36)
.justifyContent(FlexAlign.Center)
Column() {
Text('石天雄')
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text('已陪伴 3 只萌宠 892 天')
.fontSize(12)
.fontColor(COLORS.textSecondary)
.margin({ top: 4 })
}
.margin({ left: 12 })
.alignItems(VerticalAlign.Top)
Blank()
Text('⚙️').fontSize(20)
}
.width('92%')
.backgroundColor(COLORS.cardBg)
.borderRadius(16)
.padding(16)
.margin({ bottom: 12 })
// 区块二:消费统计图表
this.chartCard()
// 区块三:任务清单
Column() {
Text('今日任务')
.fontSize(15)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 8 })
ForEach(this.tasks, (task: PetTask) => {
Row() {
// 左侧色条(优先级颜色)
Column()
.width(4)
.height(40)
.backgroundColor(taskColor(task.priority))
.borderRadius(2)
// 任务信息
Column() {
Text(task.title)
.fontSize(13)
.fontWeight(FontWeight.Medium)
.decoration({
type: task.done ? TextDecorationType.LineThrough : TextDecorationType.None,
color: COLORS.textTertiary
})
Text(task.time)
.fontSize(11)
.fontColor(COLORS.textTertiary)
.margin({ top: 2 })
}
.margin({ left: 8 })
Blank()
// 完成状态切换
Text(task.done ? '✅' : '⬜')
.fontSize(16)
.onClick(() => {
task.done = !task.done;
})
}
.width('100%')
.backgroundColor(COLORS.cardBg)
.borderRadius(8)
.padding(8)
.margin({ bottom: 6 })
}, (task: PetTask, idx: number) => `${task.title}_${idx}`)
}
.width('92%')
.backgroundColor(COLORS.cardBg)
.borderRadius(16)
.padding(16)
.margin({ bottom: 16 })
}
.width('100%')
.padding({ top: 12 })
}
用户信息卡片使用 72vp 圆形头像(borderRadius(36))+ 右侧两行文字(名字 + 陪伴标语)+ 右侧设置按钮的三段式布局,与档案 Tab 的宠物信息卡片风格统一但尺寸更大,突出"我的"页面的个人中心属性。
任务清单的设计亮点在于左侧 4vp 宽色条,颜色由 taskColor 函数根据优先级动态计算——高优先级红色、中优先级橙色、低优先级绿色。色条高度 40vp 与任务卡片高度匹配,borderRadius(2) 赋予轻微圆角。
完成任务的核心交互是 onClick 中直接翻转 task.done 布尔值。由于 PetTask 是 @Observed 类,@State tasks 数组中的元素属性变化会触发引用该元素的 UI 重新渲染——TextDecorationType.LineThrough(删除线)会自动出现/消失,emoji 从 ⬜ 变为 ✅,无需手动更新 UI。
十五、图表卡片分析(chartCard)
@Builder
chartCard() {
Column() {
Row() {
Text('消费统计')
.fontSize(15)
.fontWeight(FontWeight.Bold)
Blank()
Text('近6个月')
.fontSize(11)
.fontColor(COLORS.textTertiary)
}
.width('100%')
.margin({ bottom: 12 })
// 柱状图
Row() {
ForEach(CHART_DATA, (item, idx: number) => {
Column() {
// 柱子
Column()
.width(20)
.height(item.value / 100)
.backgroundColor(idx === CHART_DATA.length - 1 ? COLORS.accent : COLORS.warm)
.borderRadius(4)
// 月份标签
Text(item.label)
.fontSize(10)
.fontColor(COLORS.textTertiary)
.margin({ top: 4 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
}, (item, idx: number) => `${item.label}_${idx}`)
}
.width('100%')
.height(80)
.alignItems(VerticalAlign.Bottom)
}
.width('92%')
.backgroundColor(COLORS.cardBg)
.borderRadius(16)
.padding(16)
.margin({ bottom: 12 })
}
图表卡片实现了一个纯 UI 柱状图,无需引入图表库。核心原理是:每个柱子使用 Column 组件,高度设为 item.value / 100(如 5200 / 100 = 52vp),通过数值到高度的线性映射实现可视化。柱子宽度固定 20vp,圆角 4vp。
颜色策略上,最新月份(idx === CHART_DATA.length - 1)使用强调色 COLORS.accent(橙色),其余月份使用暖色 COLORS.warm(棕色),引导用户关注最新数据。
外层 Row 设置 .alignItems(VerticalAlign.Bottom) 确保所有柱子底部对齐,月份标签在柱子下方。每个 Column 使用 layoutWeight(1) 等分宽度,6 根柱子均匀分布。
这种柱状图方案的优势在于零依赖、高可控,缺点是不支持交互(如点击查看详情)和动画。在数据量小(6 个数据点)的场景下完全够用。
十六、底部 Tab 栏分析(tabBar)
@Builder
tabBar() {
Row() {
ForEach(TAB_LIST, (tab, idx: number) => {
Column() {
Text(tab.icon)
.fontSize(22)
.opacity(this.currentTab === idx ? 1.0 : 0.5)
Text(tab.label)
.fontSize(10)
.fontColor(this.currentTab === idx ? COLORS.accent : COLORS.textTertiary)
.margin({ top: 2 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
.onClick(() => {
this.currentTab = idx;
this.activeTabLabel = tab.label;
})
}, (tab, idx: number) => `${tab.label}_${idx}`)
}
.width('100%')
.height(56)
.backgroundColor(COLORS.cardBg)
.border({ width: { top: 1 }, color: COLORS.divider })
}
底部 Tab 栏使用 Row + 6 个等宽 Column(各 layoutWeight(1)),每项包含 emoji 图标和标签文字。选中态通过两个维度的视觉变化体现:图标 opacity 从 0.5 提升至 1.0,标签文字颜色从三级文字色变为强调色。这种双重反馈确保用户即使在户外强光下也能清晰辨识当前 Tab。
顶部边框使用 .border({ width: { top: 1 }, color: COLORS.divider }) 仅渲染上边框,在 Tab 栏与内容区之间形成细腻的分界线。
点击事件仅需两行代码——设置 currentTab 索引和 activeTabLabel 名称,ArkUI 自动完成内容区切换、选中态样式更新、滚动位置重置等全部 UI 操作,充分体现了声明式 UI 的简洁性。
十七、弹窗系统分析
弹窗系统由遮罩层和三个弹窗 Builder 组成,通过 showModal、modalType、editTarget 三个状态变量协作控制。
17.1 遮罩层
@Builder
modalOverlay() {
if (this.showModal) {
Stack({ alignContent: Alignment.Center }) {
// 半透明遮罩
Column()
.width('100%')
.height('100%')
.backgroundColor(COLORS.overlay)
.onClick(() => {
this.showModal = false;
})
// 弹窗内容
if (this.modalType === 'add') {
this.modalAdd()
} else if (this.modalType === 'edit') {
this.modalEdit()
} else if (this.modalType === 'delete') {
this.modalDelete()
}
}
.width('100%')
.height('100%')
}
}
遮罩层使用 Stack 叠加布局,底层是 #00000066(40% 透明黑色)的全屏遮罩,上层根据 modalType 值条件渲染三种弹窗。点击遮罩区域关闭弹窗——这是移动端标准的交互模式。
if (this.showModal) 条件确保弹窗关闭时组件从渲染树中移除,而非仅隐藏,节省内存。
17.2 新增弹窗(modalAdd)
@Builder
modalAdd() {
Column() {
Text('新增服务')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 16 })
TextInput({ placeholder: '服务名称' })
.width('100%')
.height(40)
.borderRadius(8)
.border({ width: 1, color: COLORS.border })
// 更多输入框...
Row() {
Text('取消')
.layoutWeight(1)
.height(40)
.textAlign(TextAlign.Center)
.backgroundColor(COLORS.warmLight)
.borderRadius(8)
.onClick(() => {
this.showModal = false;
})
Text('确定')
.layoutWeight(1)
.height(40)
.textAlign(TextAlign.Center)
.backgroundColor(COLORS.accent)
.fontColor('#FFFFFF')
.borderRadius(8)
.margin({ left: 8 })
.onClick(() => {
this.showModal = false;
})
}
.width('100%')
.margin({ top: 16 })
}
.width('80%')
.backgroundColor(COLORS.cardBg)
.borderRadius(16)
.padding(20)
}
新增弹窗包含标题、多个 TextInput 输入框和取消/确定双按钮。按钮使用 layoutWeight(1) 等分宽度,确定按钮使用强调色背景 + 白色文字,取消按钮使用浅暖色背景,形成主次按钮的视觉层级。
17.3 编辑弹窗(modalEdit)与删除弹窗(modalDelete)
编辑弹窗与新增弹窗结构类似,但会从 editTarget 读取已有数据填充表单。删除弹窗更简洁,仅展示确认文案和取消/确认按钮,确认按钮使用 COLORS.danger(红色)背景以警示操作风险。
十八、功能模块对比表
| 模块 | 布局方式 | 数据模型 | 字段数 | 核心操作 | 动画效果 | 状态颜色 | 数据量 | 特殊组件 |
|---|---|---|---|---|---|---|---|---|
| 首页 | 双列卡片网格 | PetService | 6 | 点击卡片 | — | — | 6 | slice分批ForEach |
| 附近 | 水平分栏列表 | PetShop | 5 | 查看详情 | — | 评分→星星emoji | 6 | 嵌套ForEach标签 |
| 订单 | 时间轴卡片 | PetOrder | 5 | 编辑/删除 | — | 状态→颜色映射 | 6 | Line时间轴连线+Circle圆点 |
| 档案 | 大卡片+四宫格 | PetProfile | 6 | 编辑 | — | — | 3 | Divider分割线+四宫格 |
| 社区 | 横滚筛选+信息流 | PetPost | 6 | 关注/删除 | — | 选中态切换 | 6 | 水平Scroll分类条 |
| 我的 | 三段式区块 | PetTask + CHART_DATA | 4+2 | 完成任务 | — | 优先级→色条 | 6 | 纯UI柱状图+色条 |
| 头部 | Stack叠加 | — | — | 通知 | 呼吸动画 | — | — | 线性渐变背景 |
| 图表 | 柱状图 | CHART_DATA | 2 | — | — | 最新→强调色 | 6 | Column高度映射 |
| Tab栏 | 等分图标行 | TAB_LIST | 2 | 切换Tab | — | 选中→强调色 | 6 | opacity双态 |
| 弹窗 | Stack遮罩 | 联合类型 | — | 新增/编辑/删除 | — | 删除→危险色 | — | 条件渲染三弹窗 |
十九、总结与展望
19.1 技术总结
本文剖析的萌宠家宠物服务平台,完整展示了基于 HarmonyOS ArkUI 框架构建多场景应用的核心技术方案。从架构层面看,应用采用了四层设计——常量与工具层提供色彩和数据基础设施,数据模型层通过 @Observed 实现可观察性,组件层通过 @State 管理响应式状态,Builder 层通过 13 个 @Builder 函数拆分渲染逻辑。
六个 Tab 的布局策略各不相同——双列网格、分栏列表、时间轴、大卡片、信息流、三段式——确保了视觉差异化和用户体验的丰富性。每个布局都不是随意选择,而是根据内容特征量身设计:服务推荐需要网格化浏览,商家信息需要左右分栏,订单流程需要时间轴暗示进度,宠物档案需要大卡片突出重要性,社区动态需要信息流式浏览,个人中心需要多区块聚合。
19.2 关键技术决策回顾
| 决策 | 选择 | 替代方案 | 选择理由 |
|---|---|---|---|
| 状态管理 | @Observed + @State | AppStorage 全局状态 | 六 Tab 数据各自独立,无需跨组件共享 |
| 动画方案 | 单 setInterval + 布尔翻转 | 多 animateTo 调用 | 全局仅一个定时器,性能开销最小 |
| 图标方案 | emoji 字符 | Image 组件 + 图片资源 | 零依赖、即改即显、包体积零增加 |
| 柱状图 | Column 高度映射 | 第三方图表库 | 数据量小,纯 UI 方案够用且可控 |
| Tab 切换 | if-else 条件渲染 | Swiper 组件 | 条件渲染只保留当前 Tab 组件,内存更省 |
| 文字溢出 | maxLines + Ellipsis | 截断或自动缩小 | 省略号保留信息提示,不破坏布局 |
| 状态颜色 | 工具函数 + Record 映射 | 硬编码颜色值 | 颜色策略集中管理,易维护易扩展 |
19.3 展望
当前实现已在视觉层、交互层、状态管理层达到了生产级 Demo 的标准,但仍有以下可优化空间:
- 网络请求层:当前使用 Mock 数据,实际应用需引入
@ohos.net.http或Retrofit风格的网络框架,增加请求拦截、错误重试、缓存策略 - 持久化存储:宠物档案、任务清单等用户数据需通过
@ohos.data.preferences或 SQLite 持久化,确保应用重启后数据不丢失 - 组件抽取:13 个 Builder 函数可进一步抽取为独立组件文件,通过
@Component export struct实现跨页面复用 - 暗色模式:COLORS 常量需改造为根据
ConfigurationConstant.ColorMode动态切换的双色板 - 无障碍支持:emoji 图标对屏幕阅读器不友好,需补充
accessibilityText属性 - 动画丰富度:可在 Tab 切换时增加
transition转场动画,在卡片点击时增加scale缩放反馈
鸿蒙 ArkUI 的声明式范式让"多场景差异化布局 + 统一状态管理"成为自然而非勉强的选择。随着 OpenHarmony 生态的持续扩展,基于 ArkUI 的行业应用将拥有更广阔的实践空间。
附录:DevEco Studio 创建新项目与查看 SDK 版本
本章节演示如何使用 DevEco Studio 创建一个 HarmonyOS 新项目,并查看当前 IDE 已安装的 SDK 版本,适合作为其他技术博文的补充操作指南。
一、创建新项目
1.1 进入欢迎界面
启动 DevEco Studio 后,首先看到的是欢迎界面。左侧导航栏默认选中 “项目”,右侧提供三个主要入口:
- 新建项目:从头创建新项目
- 打开项目:打开本地已有项目
- 克隆仓库:从 Git 等版本控制拉取代码
点击 “新建项目” 按钮,进入项目创建向导。

1.2 选择项目模板
在弹出的"新建项目"对话框中,左侧分类标签提供了两种项目类型:
| 类型 | 说明 |
|---|---|
| 应用(Application) | 开发标准的 HarmonyOS 应用,具备完整的 Ability 生命周期 |
| 元服务(Atomic Service) | 开发轻量级的原子化服务,无需安装即可使用 |
选择 “应用” 标签后,右侧展示多种模板。对于大多数场景,推荐选择 “Empty Ability” —— 这是一个最基础的入门模板,仅包含 Hello World 功能,适合从零开始构建应用。

1.3 配置项目信息
点击 “下一步” 后,进入项目配置界面,需要填写以下核心参数:
| 配置项 | 示例值 | 说明 |
|---|---|---|
| 项目名称(Project name) | rollboat |
应用的项目名称,建议使用英文命名 |
| 包名(Bundle name) | com.rollboat.myapplication |
应用唯一标识,采用反向域名格式 |
| 保存路径(Save location) | D:\CodeFactory\rollboat |
项目本地存储路径,避免使用中文和空格 |
| 兼容 SDK(Compatible SDK) | 6.1.1(24) |
目标 HarmonyOS API 版本,点击"查看参考"可了解各版本差异 |
| 模块名称(Module name) | entry |
主模块名称,默认 entry 为应用入口模块 |
| 设备类型(Device types) | ☑ Phone | 勾选目标设备:Phone / Tablet / 2in1 / Car / Wearable / TV |
右侧预览区会实时展示当前模板的默认效果 —— 一个居中显示的 “Hello World” 文本。

1.4 完成创建
确认配置无误后,点击右下角 “完成” 按钮,IDE 将自动执行以下操作:
- 生成项目骨架(Stage 模型目录结构)
- 执行
ohpm install安装依赖 - 运行 Hvigor 构建初始化(
Build Init)
构建日志中显示 “退出代码为 0” 表示项目初始化成功。

1.5 项目结构概览
创建完成后,左侧项目面板展示的是标准的 Stage 模型 目录结构:
rollboat/
├── .hvigor/ # Hvigor 构建工具缓存
├── .idea/ # IDE 配置文件
├── AppScope/ # 应用级全局配置
│ └── app.json5
├── entry/ # 主模块(入口模块)
│ ├── src/main/ets/
│ │ ├── entryability/ # Ability 生命周期管理
│ │ │ └── EntryAbility.ets
│ │ └── pages/ # UI 页面
│ │ └── Index.ets # 首页(默认 Hello World)
│ ├── src/main/resources/ # 资源文件
│ ├── module.json5 # 模块配置
│ └── build-profile.json5 # 构建配置
├── oh_modules/ # OHPM 依赖包
├── build-profile.json5 # 工程构建配置
├── hvigorfile.ts # Hvigor 构建脚本
└── oh-package.json5 # 包管理配置
核心文件 Index.ets 的默认代码如下,采用 ArkTS 声明式 UI 语法:
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
RelativeContainer() {
Text(this.message)
.id('HelloWorld')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.onClick(() => {
this.message = 'Welcome';
})
}
.height('100%')
.width('100%')
}
}
| 关键语法 | 作用 |
|---|---|
@Entry |
标记为页面入口,可用于路由跳转 |
@Component |
声明为自定义组件 |
@State |
状态变量,数据变更时自动触发 UI 刷新 |
RelativeContainer |
相对布局容器,替代传统线性布局 |
.onClick() |
点击事件,此处点击后文本变为 “Welcome” |
打开右侧 Previewer(预览器),选择 Phone 设备,即可实时预览 Hello World 效果,无需连接真机或启动模拟器。

二、查看 SDK 版本
2.1 查看 HarmonyOS SDK
DevEco Studio 安装时已内置 HarmonyOS SDK,无需单独下载。通过以下路径查看:
文件 → 设置 → HarmonyOS SDK(或快捷键
Ctrl + Alt + S搜索 “HarmonyOS SDK”)
在设置面板中,可以看到当前已安装的 SDK 版本信息:
| 名称 | 阶段 | 状态 |
|---|---|---|
| HarmonyOS 6.1.1 | Release | ✅ 已安装 |
界面顶部提示:“HarmonyOS SDK 已经包含在 IDE,无需单独安装”,省去了手动配置 SDK 的繁琐步骤。

2.2 查看 ArkUI-X SDK(跨平台扩展)
如果项目需要将 ArkUI 框架扩展到多个 OS 平台(Android / iOS / OpenHarmony),还需要配置 ArkUI-X SDK。路径如下:
文件 → 设置 → 语言和框架 → ArkUI-X
在这里可以查看已安装和可选的 ArkUI-X SDK 版本:
| 版本 | SDK 版本号 | 阶段 | 状态 |
|---|---|---|---|
| API Version 24 | 6.1.1.100 | Release | ✅ 已安装 |
| API Version 23 | 6.1.0.28 | Beta1 | 未安装 |
| API Version 22 | 6.0.2.112 | Release | 未安装 |
安装路径示例:D:\DevTools\ArkUI-X\sdk
说明:ArkUI-X 允许开发者使用一套 ArkTS 主代码,同时构建多平台应用。如果仅开发 HarmonyOS 原生应用,无需额外安装 ArkUI-X SDK。

三、小结
| 步骤 | 操作 | 关键点 |
|---|---|---|
| 创建项目 | 欢迎页 → 新建项目 → 选择 Empty Ability 模板 → 配置项目信息 → 完成 | 使用 Stage 模型 + ArkTS 语言 |
| 查看 SDK | 设置 → HarmonyOS SDK | SDK 已内置,无需手动安装 |
| 跨平台扩展 | 设置 → ArkUI-X | 根据需要安装对应 API 版本 |
至此,DevEco Studio 的项目创建与 SDK 环境确认全部完成,可以开始 HarmonyOS 应用的功能开发。
本文基于 DevEco Studio 6.1.1 Release 版本编写,不同版本界面可能存在细微差异。
更多推荐

所有评论(0)