@Entry 与 @Component 装饰器:组件声明、导出与页面入口
前言在 ArkUI 中装饰器是声明式 UI 的核心语法。Entry和Component是最基础也是最重要的两个装饰器它们分别用于声明页面入口和自定义组件。“海风日记“共有37 个 .ets 源文件每个文件都使用了Component或Entry装饰器。本文将从源码出发深入讲解这两个装饰器的语法、机制、生命周期以及最佳实践帮助你全面掌握 ArkUI 的组件化开发。一、装饰器概述1.1 什么是装饰器装饰器是 ArkTS 语言提供的一种声明式语法用于为类或类成员添加元数据和行为。在 ArkUI 中装饰器主要用于声明组件Component将一个类标记为 UI 组件声明页面入口Entry将一个组件标记为独立页面状态管理State、Prop、Link等管理组件状态构建函数Builder封装 UI 构建逻辑1.2 Entry 与 Component 的关系装饰器作用是否必须使用场景Component声明这是一个 UI 组件是所有组件必须使用Entry声明这是一个页面入口否仅页面需要注册在 main_pages.json 中的页面// 页面组件同时使用 Entry 和 Component Entry Component struct SplashPage { ... } // 普通组件只使用 Component Component export struct DiaryCard { ... }1.3 海风日记中的组件统计类型装饰器数量示例页面组件Entry Component26 个SplashPage,Index.ets通用组件Componentexport4 个DiaryCard,MoodSelector内部组件Component不导出7 个ReviewTab内的统计卡片二、Component 装饰器详解2.1 基本语法Component struct ComponentName { // 状态变量 State message: string Hello // 构建方法 build() { // 返回 UI 描述 Column() { Text(this.message) } } }2.2 Component 的规则必须使用 structComponent只能装饰struct类型必须包含 build() 方法build()返回组件的 UI 描述build() 必须有且只有一个根节点根节点可以是 Column、Row、Stack 等容器不支持继承Component修饰的 struct 不能继承其他类2.3 可导出与不可导出// 可导出的组件供其他文件 import 使用 Component export struct DiaryCard { // 属性声明 moodColor: MoodColor default content: string build() { Row() { ... } } } // 不导出的组件仅在本文件内使用 Component struct InnerComponent { build() { Column() { ... } } }2.4 组件属性Component中的非State属性可以通过构造函数参数传递Component export struct DiaryCard { // 这些属性可以通过父组件传入 moodColor: MoodColor default timeStr: string content: string tags: string[] [] isPinned: boolean false hasImage: boolean false moodEmoji: string onTap: () void () {} // 函数类型属性 build() { Row() { // 使用属性构建 UI Text(this.content) } .onClick(() { this.onTap() }) } } // 在父组件中使用 DiaryCard({ moodColor: getMoodColor(item.mood), timeStr: 今天 · 06:12, content: item.content, tags: item.tags, isPinned: item.isPinned, hasImage: item.imageUrls.length 0, moodEmoji: getMoodEmoji(item.mood), onTap: () { router.pushUrl({ url: pages/diary/DiaryDetailPage }) } })三、Entry 装饰器详解3.1 基本语法Entry Component struct SplashPage { build() { Stack() { // 页面内容 } .width(100%) .height(100%) } }3.2 Entry 的作用Entry做了以下事情注册页面将该组件注册为可被路由跳转的页面提供生命周期添加aboutToAppear()、aboutToDisappear()、onPageShow()、onPageHide()等生命周期回调绑定路由参数可以通过router.getParams()获取路由参数3.3 Entry 的生命周期Entry Component struct DiaryDetailPage { aboutToAppear() { // 1. 页面即将显示时调用 // 适合获取路由参数、初始化数据 const params router.getParams() as Recordstring, string if (params?.diaryId) { this.diaryId params.diaryId } } onPageShow() { // 2. 页面显示时调用每次回到该页面都会触发 // 适合刷新数据、恢复状态 this.refreshData() } onPageHide() { // 3. 页面隐藏时调用 // 适合暂停动画、保存草稿 } aboutToDisappear() { // 4. 页面即将销毁时调用 // 适合清理资源、取消订阅 this.cleanup() } }3.4 生命周期执行顺序页面启动时的生命周期顺序1. aboutToAppear() ← 页面即将显示 2. build() ← 构建 UI 3. onPageShow() ← 页面已显示页面跳转到其他页面的生命周期顺序1. onPageHide() ← 当前页面隐藏 2. aboutToAppear() ← 新页面即将显示 3. build() ← 新页面构建 4. onPageShow() ← 新页面已显示四、组件导出与导入4.1 export 导出组件// DiaryCard.ets Component export struct DiaryCard { // 组件定义 } // MoodSelector.ets Component export struct MoodSelector { // 组件定义 } // WaveHeaderBand.ets Component export struct WaveHeaderBand { // 组件定义 }4.2 import 导入组件// HomeTab.ets — 导入组件 import { DiaryCard } from ../../common/components/DiaryCard import { WaveHeaderBand } from ../../common/components/WaveHeaderBand // CalendarTab.ets — 导入数据和模型 import { MOCK_DIARIES } from ../../common/model/DiaryModel import { COLOR_PRIMARY } from ../../common/constants/Colors // Index.ets — 导入子页面组件 import { HomeTab } from ./home/HomeTab import { CalendarTab } from ./calendar/CalendarTab import { ReviewTab } from ./review/ReviewTab import { MineTab } from ./mine/MineTab4.3 导入路径的规则当前文件: pages/home/HomeTab.ets 导入组件: ../../common/components/DiaryCard.ets ↑↑ 从当前目录上溯两级到 common路径说明./当前目录../上一级目录../../上两级目录common/components/通用组件目录common/model/数据模型目录common/constants/常量目录五、Component 中的状态管理5.1 State 装饰器State标记的变量发生变化时组件会自动重新渲染Component export struct HomeTab { State isGridView: boolean true State diaryList: DiaryEntry[] MOCK_DIARIES build() { Column() { // 切换视图 Button() .onClick(() { this.isGridView !this.isGridView }) // 根据 isGridView 状态渲染不同布局 if (this.isGridView) { Grid() { ... } // 双栏网格 } else { List() { ... } // 单栏列表 } } } }5.2 Link 装饰器Link实现父子组件之间的双向绑定// 父组件 Component export struct WriteDiaryPage { State selectedMood: number 3 State selectedWeather: number 0 build() { MoodSelector({ selectedMood: this.selectedMood, // 传入 State selectedWeather: this.selectedWeather // 传入 State }) } } // 子组件 Component export struct MoodSelector { Link selectedMood: number // Link 双向绑定 Link selectedWeather: number // Link 双向绑定 build() { Column() { // 修改 Link 变量会同步到父组件的 State Text() .onClick(() { this.selectedMood 4 }) } } }5.3 State 与 Link 的对比装饰器数据流向声明位置修改权限State内部状态组件内部仅本组件可修改Prop父→子单向子组件子组件可修改但不会同步回父组件Link双向绑定子组件子组件修改会同步回父组件5.4 状态管理的最佳实践// 1. 状态尽量定义在需要修改的组件中 State currentIndex: number 0 // Index 中定义Index 修改 // 2. 子组件通过 Link 获取修改能力 Link selectedMood: number // MoodSelector 中修改同步到父组件 // 3. 纯展示数据通过普通属性传递 content: string // DiaryCard 中仅展示不修改六、组件设计模式6.1 容器组件模式容器组件负责布局和状态管理子组件负责具体展示// Index.ets — 容器组件 Entry Component struct Index { State currentIndex: number 0 build() { Tabs() { TabContent() { HomeTab() } // 子组件 TabContent() { CalendarTab() } // 子组件 TabContent() { ReviewTab() } // 子组件 TabContent() { MineTab() } // 子组件 } } }6.2 展示组件模式展示组件专注于 UI 呈现不管理业务状态// DiaryCard.ets — 纯展示组件 Component export struct DiaryCard { // 所有属性由父组件传入 moodColor: MoodColor default timeStr: string content: string tags: string[] [] isPinned: boolean false hasImage: boolean false moodEmoji: string onTap: () void () {} build() { // 仅 UI 展示不包含业务逻辑 } }6.3 组件粒度控制粒度特点适用场景示例粗粒度代码集中耦合度高简单页面FaqPage中粒度适度拆分可复用通用功能DiaryCard细粒度高度复用代码分散多处使用MoodSelector七、组件生命周期详解7.1 页面组件的完整生命周期Entry Component struct ExamplePage { // 1. 构造函数 constructor() { console.info(constructor) } // 2. 状态初始化 State count: number 0 // 3. aboutToAppear页面即将显示 aboutToAppear() { console.info(aboutToAppear) } // 4. build构建 UI build() { Column() { Text(${this.count}) } .onClick(() { this.count }) } // 5. onPageShow页面已显示 onPageShow() { console.info(onPageShow) } // 6. onPageHide页面隐藏 onPageHide() { console.info(onPageHide) } // 7. aboutToDisappear页面即将销毁 aboutToDisappear() { console.info(aboutToDisappear) } }7.2 非页面组件的生命周期非Entry组件只有aboutToAppear和aboutToDisappearComponent export struct DiaryCard { aboutToAppear() { // 组件即将显示 } aboutToDisappear() { // 组件即将销毁 } }7.3 生命周期使用场景生命周期回调典型用途aboutToAppear获取路由参数、初始化数据、发起网络请求onPageShow每次页面显示时刷新数据onPageHide暂停动画、保存草稿、释放临时资源aboutToDisappear清理定时器、取消订阅、释放内存八、常见问题与最佳实践8.1 组件未注册问题使用Component装饰的组件在页面中不显示。原因组件未使用export导出或在父组件中未正确import。解决方案// 1. 导出组件 Component export struct MyComponent { ... } // 2. 导入组件 import { MyComponent } from ./path/to/MyComponent8.2 build() 方法缺少根节点问题编译报错提示build()必须包含一个根节点。解决方案使用容器组件包裹多个子元素build() { // 错误多个子组件没有根节点 // Text(Hello) // Text(World) // 正确使用 Column 作为根节点 Column() { Text(Hello) Text(World) } }8.3 State 更新不触发 UI 刷新问题修改了State变量但 UI 没有更新。原因直接修改了数组或对象的内部属性未触发引用变化。解决方案创建新的数组或对象引用// 错误直接修改数组内部 this.tags.splice(idx, 1) // UI 不会刷新 // 正确创建新数组 this.tags [...this.tags] // 触发 UI 刷新总结本文详细讲解了 ArkUI 中Entry和Component两个核心装饰器的完整用法Component 基础组件声明、build() 方法、导出规则Entry 装饰器页面入口注册、生命周期回调组件导入导出export 和 import 的使用方法状态管理State、Link、Prop 的对比和使用组件设计模式容器组件、展示组件、粒度控制生命周期页面组件和普通组件的生命周期差异最佳实践常见问题的排查和解决方案至此第一系列“应用架构与导航“的 10 篇文章全部完成从下一篇文章开始我们将进入第二系列闪屏与引导页深入讲解 Canvas 2D 绘制、LinearGradient 渐变、Swiper 轮播等内容敬请期待。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源Component 装饰器文档Entry 装饰器文档ArkUI 组件生命周期海风日记项目源码State 状态管理文档Link 装饰器文档开源鸿蒙跨平台社区[HarmonyOS 开发者官网](https://atomgit.com/openharmony/docs

相关新闻

最新新闻

日新闻

周新闻

月新闻