# 组件属性
组件可以定义一些属性,接收组件使用者传入的值。组件的使用者可以在 WXML 节点中指定属性对应的值。
# 定义属性
Definition 形式定义属性形如:
export default Component({
properties: {
fooProp: {
type: String,
value: '',
},
},
})
Chaining 形式定义属性形如:
export default Component()
.property('fooProp', {
type: String,
value: '',
})
.register()
上例中定义了 fooProp 属性,定义时提供的 type 表示类型,value 表示初始值。
定义了属性之后,组件的使用者就可以在 WXML 节点中指定属性对应的值,例如在页面中:
<!-- page/index/index.wxml -->
<custom-component foo-prop="bar" />
在 WXML 中,驼峰写法的属性名可以换成连字符写法(也可以仍然使用驼峰写法)。
对组件属性命名时,需要注意:
- 属性名不能与 data 数据字段重名;
idclassstyleslot是 WXML 保留属性,虽然可以设为组件属性,但无法在 WXML 中对它们赋值;dataXxx这样的属性名也无法在 WXML 中对它们赋值,因为data-xxx=""会被视为 dataset 。
# 属性类型与简化定义
属性支持下表中的类型。
| 类型 | 默认值 | 说明 |
|---|---|---|
String | '' | 字符串 |
Number | 0 | 数值 |
Boolean | false | 布尔值 |
Object | null | 对象 |
Array | [] | 数组 |
Function | function () {} | 函数 |
null | null | 表示属性支持任意类型 |
Function类型仅 glass-easel 组件框架支持。在 exparser 组件框架中不能传递函数类型的属性,但可以将函数作为Object类型中的一个字段来传递。
如果一个属性的初始值 value 与它的类型默认值相同,就可以将属性定义简写为 type 本身,例如:
export default Component({
properties: {
fooProp: String,
},
})
export default Component()
.property('fooProp', String)
.register()
# 初始值和默认值
初始值 指的是一个属性未被指定值时所具有的值。
默认值 指的是一个属性未被指定值时所具有的值,或被赋予非法值时用于代替非法值的属性值。仅 glass-easel 组件框架支持。默认值应使用一个函数来指定,形如:
export default Component({
properties: {
fooProp: {
type: String,
default: () => 'DEFAULT',
},
},
})
export default Component()
.property('fooProp', {
type: String,
value: () => 'DEFAULT',
})
.register()
如果指定了默认值 default,初始值 value 不能被指定。
# 属性值类型转换
在 WXML 中为一个属性指定值时,会自动进行类型转换;如果转换失败,则视为非法值(将使用默认值代替)。type 为 null 的属性不会进行类型转换。
例如,如果 custom-component 组件的 num-prop 属性是 Number 类型的,而在使用者的 WXML 中:
<custom-component num-prop="1" />
这种情况下 num 属性会接收到数值 1。
# 布尔类型属性值转换
对于 Boolean 类型的属性,如果在 WXML 中未指定值,会自动将其值为 true。
<custom-component bool-prop />
<!-- 等价于 -->
<custom-component bool-prop="ANY" />
<!-- 等价于 -->
<custom-component bool-prop="{{true}}" />
想要把它指定为 false,必须使用数据绑定写法,例如:
<custom-component bool-prop="{{false}}" />
# 对象、数组类型属性值转换
对象和数组只能使用数据绑定写法,例如:
<custom-component array-prop="{{ [1, 2] }}" object-prop="{{ { a: 1, b: 2 } }}" />
在 glass-easel 组件框架中,绑定对象外层的花括号可以省略:
<custom-component object-prop="{{ a: 1, b: 2 }}" />
# 可选类型
如果一个属性可能接受多种类型的值,可以用 optionalTypes 为它附加多个类型。例如:
export default Component({
properties: {
fooProp: {
type: String,
optionalTypes: [String, Boolean],
},
},
})
export default Component()
.property('fooProp', {
type: Number,
optionalTypes: [String, Boolean],
})
.register()
# 使用 TypeScript 指定对象类型
使用 TypeScript 时,对于 type 为 Array 或 Object 的属性,会根据它初始值、默认值的类型作为这个属性字段的具体类型,来进行类型推断。
此时,可以通过 as 来指定具体类型:
export default Component()
.property('objectProp', {
type: Object,
value: {} as {
foo?: number
bar?: string
},
})
.register()
# 属性值变化监听器
属性值可以指定一个 observer,当属性值发生变化时,会调用这个函数。
export default Component()
.property('foo', {
type: String,
observer(newVal, oldVal) {
// 属性值变化后触发
},
})
.register()
如果需要在 observer 中同步执行 setData 等更新操作,更推荐使用 数据监听器 ,因为通常它有更好的性能。
对于 type 为 Object 或 Array 的属性,如果通过该组件自身的 this.setData 来改变属性值的一个子字段,则依旧会触发属性 observer,且 observer 接收到的 newVal 是变化的那个子字段的值。
# 属性值比较器
仅 glass-easel 组件框架支持。
每当组件的使用者进行更新时,组件框架需要判断它使用的每个子组件是不是被更新了。框架的判断方法是,对比每个属性值,如果属性值不一样,就认为子组件被更新了。如果子组件被更新了,就会产生一定的更新开销。
对于子组件属性是数值、字符串、布尔值等基本类型时,框架可以直接对比它们的值。但对于对象、数组这样的值,框架难以比较,常常将它们直接视为被更新了。
此时可以通过 comparer 来指定一个属性值比较函数,避免不必要的更新、提升整体性能。如果 comparer 返回真,表示属性值变化了、组件需要更新。例如:
export default Component()
.property('objectProp', {
type: Object,
comparer(newValue, oldValue) {
return newValue.foo !== oldValue.foo || newValue.bar !== oldValue.bar
},
})
.register()
# 页面根组件的属性值
对于页面根组件,属性值会从页面的 query 参数中获取(参数值会被自动 URL decode)。例如:
// pages/index/index.js
export default Component()
.property('strProp', String)
.property('numProp', Number)
.register()
如果页面以 pages/index/index?strProp=foo&numProp=1 打开,那么 strProp 会被赋值 'foo',numProp 会被赋值 1。
由于 query 参数是字符串,页面根组件的属性值应当是 String 或 Number 类型的。