HarmonyOS 鸿蒙 ArkUI 保留属性名踩坑实录 —— 那些「看起来能命名、一编译就报错」的 @Prop
一、现象:同一个坑,项目里踩了五次
这个项目做了十几个组件,但「保留属性名冲突」这个坑,在至少五个地方留下了注释痕迹:
// FlowAvatar.ets
/** Logical pixel size. Named avatarSize because `size` is an ArkUI attribute. */
@Prop avatarSize: number = 64;
/** Depth shadow. Named showShadow because `shadow` is an ArkUI attribute. */
@Prop showShadow: boolean = true;
// ThinkingOrb.ets
/** Logical preset size. Named orbSize because `size` is an ArkUI attribute. */
@Prop orbSize: ThinkingOrbSize = ThinkingOrbSize.Avatar;
// BorderBeam.ets
/** Corner radius in vp. Named beamRadius because borderRadius is an ArkUI attribute. */
@Prop beamRadius: number = -1;
/** Glow brightness multiplier. Named beamBrightness because brightness is an ArkUI attribute. */
@Prop beamBrightness: number = -1;
还有 GrokBot 的 botSize(不用 size)、SlotText 的 rollDirection(不用 direction)。
关键问题来了:为什么「给 @Prop 起名 size」会报错?这背后是 ArkUI 一个非常具体的机制,搞清楚它,你就再也不会踩。
二、根因:@Prop 名字和组件属性是同名冲突
2.1 机制
在 ArkUI 里,@Component 的 @Prop 成员,本质上会变成这个组件的构造参数 / 属性。而当你在 build() 里这样写:
build() {
Column()
.size({ width: 100, height: 100 }) // ← 通用属性 size
}
ArkUI 的「通用属性」size 是全局保留的 attribute 名。如果你的组件同时声明了:
@Prop size: number = 64;
就会产生命名冲突——编译器无法区分「这个 size 是我的 @Prop,还是 ArkUI 内置的属性」。
2.2 为什么有时候「不报错但错乱」
更危险的是部分情况不报错,但语义错乱。比如 shadow、direction、borderRadius 这些,如果只在特定上下文里冲突,编译器可能不会立刻拒绝,但你的「自定义 @Prop shadow」会和「通用阴影属性」混在一起,导致传参不生效、或者样式被意外覆盖。
这就是为什么「保留属性名」是比「保留关键字」更隐蔽的坑——它不一定报错,可能只是让你的组件行为悄悄变错。
三、高危保留名清单
基于项目里实际踩过的 + ArkUI 通用属性,整理一份「起名要避开的高危名单」:
|
想表达的含义 |
❌ 高危名 |
✅ 项目里的替代 |
|---|---|---|
|
尺寸 |
|
|
|
阴影 |
|
|
|
方向 |
|
|
|
圆角 |
|
|
|
亮度 |
|
|
|
透明度 |
|
|
|
缩放 |
|
|
|
模糊 |
|
|
通用规律:所有 ArkUI 通用属性(size、opacity、scale、rotate、blur、shadow、borderRadius、backgroundColor、padding、margin ……)以及布局方向属性(direction、align),都不该拿来给 @Prop 命名。
四、为什么「加个前缀」就够了
项目里所有的替代名都遵循同一个规律:加一个「语义前缀」,把「通用词」变成「专有词」。
|
原意 |
前缀法 |
|---|---|
|
size |
|
|
shadow |
|
|
radius |
|
|
brightness |
|
前缀的作用是消除二义性:avatarSize 明确是「这个头像组件的尺寸」,不会和 size 通用属性混淆。
但注意:前缀不能是随意的,要表达「这个组件特有的语义」。avatarSize 读起来是「头像的尺寸」,orbSize 是「状态球的尺寸」,botSize 是「机器人尺寸」——每个都落在「组件自身」的语义里,而不是泛泛的 size。
五、一个容易忽略的「边界 case」:label
项目里 GrokBot 和 GradientSpin 都用了 @Prop label:
// GrokBot.ets
@Prop label: string = 'GrokBot';
// GradientSpin.ets
@Prop label: string = 'Loading';
label 严格来说也是 ArkUI 的通用属性(Text、Button 等都有 label)。但这里它们没踩坑,原因是:
-
这些
@Prop label是自定义组件的成员,不是直接作为 ArkUI 内置属性的替代; -
组件内部是用
.accessibilityText(this.label)把值消费掉,而不是@Prop label和内置label在同一层冲突。
这提醒我们:「保留名」的判断要结合「具体冲突场景」。label 在这些组件里之所以安全,是因为它没有被用来「和内置 label 抢同一个语义槽」。但如果你在 build() 里同时写 .label(this.label) 和声明 @Prop label,就要小心了——能避开就避开,用 accessibilityLabel 或 title 更稳妥(SlotText 就用了 accessibilityLabel)。
六、落地成一条命名纪律
把坑沉淀成习惯,三条就够:
-
@Prop名字永远别和 ArkUI 通用属性撞——起名前列一下「我要表达的概念」是否在size/opacity/scale/rotate/blur/shadow/direction/borderRadius/...这个清单里。 -
撞了就加「组件语义前缀」——
avatarSize、orbSize、beamRadius,而不是mySize、size2这种无意义前缀。 -
注释里写明白「为什么叫这个名」——项目里每个改名的
@Prop上面都留了Named X because Y is an ArkUI attribute,这不是多余,而是给下一个维护者(和未来的自己)的提示,避免有人「好心」把它改回size又踩一遍。
七、总结
「保留属性名」这个坑,单独看很小,但它有三个讨厌的特质:
-
高频:几乎每个自定义组件都会碰到「尺寸/阴影/方向/圆角」这些概念。
-
隐蔽:不一定报错,可能只是行为悄悄错乱。
-
会复发:这次记住了
size,下次换个组件又踩direction。
所以它值得被单独拎出来写一篇——不是因为它复杂,而是因为它最好的解法是一份「起名 blacklist」+ 一个「加前缀」的习惯,提前防住,而不是每次报错了再改。
@Prop别叫size——叫avatarSize或orbSize。
撞了 ArkUI 通用属性,加组件语义前缀。
改了名就留注释,别让下一个人改回去再踩一遍。
这一篇,加上前面的《分层范式》《DisplaySync》《移植方法论》三篇,组成了 ArkUILab 项目在鸿蒙自定义组件开发上的完整横切方法论:怎么分层、怎么驱动帧、怎么移植、怎么命名。四篇合起来,就是一个「从零写一个可复用、可测试、可移植的鸿蒙动效组件」的完整地图。
更多推荐




所有评论(0)