组件属性

组件可以定义一些属性,用来接收组件使用者传入的值。组件的使用者可以在 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 数据字段重名;
  • id class style slot 是 WXML 的保留属性,虽然可以设为组件属性,但无法在 WXML 中对它们赋值;
  • dataXxx 这样的属性名也无法在 WXML 中对它们赋值,因为 data-xxx="" 会被视为 dataset。

属性类型与简化定义

属性支持下表中列出的类型。

类型 默认值 说明
String '' 字符串
Number 数值
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 中为一个属性指定值时,会自动进行类型转换;如果转换失败,就会被视为非法值(这时会使用默认值来代替)。typenull 的属性不会进行类型转换。

举个例子,如果 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 时,对于 typeArrayObject 的属性,会根据它初始值、默认值的类型作为这个属性字段的具体类型,来进行类型推断。

这时,可以通过 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 为 ObjectArray 的属性,如果通过该组件自身的 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 参数是字符串,页面根组件的属性值应当是 StringNumber 类型的。