一、前言
在鸿蒙项目开发中,重复编写按钮、卡片、列表项、弹窗等UI模块,会产生大量冗余代码,后续迭代维护成本陡增。ArkTS 依托 @Component 装饰器实现组件化开发,是提升开发效率、统一UI风格的核心手段。
本文从基础组件封装入手,依次讲解父子传参、双向数据绑定、公共样式抽离、性能优化,配套完整可运行代码,帮你搭建项目标准化组件体系。
二、核心装饰器与组件分类
先理清常用装饰器作用与组件类型,是组件封装的基础。
装饰器/类型 | 使用场景 | 核心特性 |
|---|
@Entry | 页面根组件 | 作为路由入口,全局唯一页面载体 |
@Component | 自定义子组件 | 可多处复用,依赖父组件传参 |
@Param | 组件入参 | 接收父组件数据,单向数据流 |
@Link | 双向绑定参数 | 父子数据互通,一方修改双方同步 |
三、基础自定义组件封装
以通用自定义按钮为例,实现基础UI封装,支持文本、尺寸、颜色自定义。
// 自定义按钮组件 CustomButton.ets@Componentexport struct CustomButton { // 接收父组件传入参数 @Param btnText: string = "默认按钮" @Param btnWidth: string = "120vp" @Param bgColor: ResourceColor = "#007DFF" build() { Button(this.btnText) .width(this.btnWidth) .backgroundColor(this.bgColor) .fontColor(Color.White) .borderRadius(8) }}
3.1 页面引入使用
import { CustomButton } from './CustomButton'@Entry@Componentstruct Index { build() { Column({ space: 20 }) { // 使用默认样式 CustomButton() // 自定义参数 CustomButton({ btnText: "提交", btnWidth: "160vp", bgColor: "#1677ff" }) } .width('100%') .padding(20) }}
四、父子组件单向传参与事件回调
@Param 为单向数据流,父组件数据更新会同步到子组件;若需要子组件向父组件传递消息,可通过自定义回调函数实现。
4.1 带回调的子组件
@Componentexport struct ClickItem { @Param content: string // 定义回调方法 @Param itemClick: () => void build() { Text(this.content) .fontSize(16) .padding(12) .backgroundColor("#f5f5f5") .onClick(() => { // 触发父组件回调 this.itemClick() }) }}
4.2 父组件接收回调
import { ClickItem } from './ClickItem'@Entry@Componentstruct Index { build() { Column() { ClickItem({ content: "点击我触发回调", itemClick: () => { console.log("子组件被点击,父组件收到通知") } }) } }}
五、@Link 双向数据绑定实战
当需要父子组件数据双向同步时,使用 @Link 装饰器。父组件使用 $$ 语法传参,子组件修改数据会直接同步回父组件。
5.1 双向绑定子组件
@Componentexport struct InputItem { // 双向绑定变量 @Link inputValue: string build() { TextInput({ text: this.inputValue }) .onChange((value: string) => { // 子组件修改,自动同步父组件 this.inputValue = value }) .width("240vp") .height("40vp") }}
5.2 父组件调用
import { InputItem } from './InputItem'@Entry@Componentstruct Index { @State msg: string = "" build() { Column({ space: 15 }) { // $$ 标记双向绑定 InputItem({ inputValue: $$this.msg }) Text(`父组件内容:${this.msg}`).fontSize(16) } .padding(20) }}
六、公共样式抽离与全局管理
将颜色、尺寸、圆角、字体等通用样式抽离为独立文件,统一管控,实现一键换肤、全局样式统一。
6.1 新建全局样式文件 style.ets
// 全局样式常量export const StyleConfig = { // 主色调 primaryColor: "#007DFF", // 辅助色 assistColor: "#666666", // 圆角 radius: 8, // 通用字体大小 fontNormal: 14, fontLarge: 18}
6.2 组件引入全局样式
import { StyleConfig } from './style'@Componentexport struct CardView { build() { Column() { Text("通用卡片") .fontSize(StyleConfig.fontNormal) .fontColor(StyleConfig.assistColor) } .width("100%") .padding(15) .borderRadius(StyleConfig.radius) .backgroundColor("#ffffff") }}
七、组件渲染优化与高频坑点
滥用@State:非动态数据不要用状态装饰器,避免无效重渲染;
@Param 直接修改:单向参数禁止在子组件内赋值,会触发报错,修改数据请用回调;
@Link 传参错误:父组件必须使用 $$,否则双向绑定失效;
样式硬编码:大量重复样式不抽离,后期维护、换肤成本极高;
组件拆分过细/过粗:合理拆分,单一职责原则,一个组件只做一件事。
八、全文总结
组件化是鸿蒙工程化开发的核心能力,合理封装通用组件,能够大幅减少重复代码、统一App UI风格、降低维护难度。
区分好 @Param 单向传参、@Link 双向绑定、事件回调的使用场景,配合全局样式抽离,就能搭建一套稳定、易扩展的组件库。本文所有代码均可直接在项目中运行,适配 API 10 及以上版本。