【小程序】自定义组件Component构造器详细总结

本文详细解释了WXML中的Component构造器,包括其属性、数据、方法、生命周期函数、数据监听机制以及组件间的通信方式。重点介绍了纯数据字段、样式隔离、组件间关系和slot的使用,为开发者构建高效、可维护的组件提供了全面指南。
摘要由CSDN通过智能技术生成

Component 构造器可用于定义组件,调用 Component 构造器时可以指定组件的属性、数据、方法等。

Component({
  behaviors: [],
 
  properties: {
    myProperty: {
      // 属性名
      type: String,
      value: '',
    },
    myProperty2: String, // 简化的定义方式
  },
 
  data: {}, // 私有数据,可用于模板渲染
 
  lifetimes: {
    created: function () {},
    attached: function () {},
    detached: function () {},
  },
 
  pageLifetimes: {
    // 组件所在页面的生命周期函数
    show: function () {},
    hide: function () {},
  },
 
  methods: {
    onMyButtonTap: function () {
      this.setData({
        // 更新属性和数据的方法与更新页面数据的方法类似
      });
    },
    // 内部方法建议以下划线开头
    _myPrivateMethod: function () {
      // 这里将 data.A[0].B 设为 'myPrivateData'
      this.setData({
        'A[0].B': 'myPrivateData',
      });
    },
    _propertyChange: function (newVal, oldVal) {},
  },
});

详细的参数含义和使用,请参考以下Component框架接口介绍:

Component(config: Object)

注册自定义组件,接受一个 Object 参数,用于描述组件的逻辑交互行为。

// 文件 /components/foo/index.js
Component({
  options: Object,
  properties: Object,
  observers: Object,
  data: Object,
  methods: Object,
  behaviors: Array,
  lifetimes: Object,
  pageLifetimes: Object,
  relations: Array,
});

完整的配置项如上所示,在自定义组件内部可通过 this 关键字访问实例对象。

 

组件 this 实例

属性

属性类型描述
isString组件的文件路径
idString节点 id
datasetString节点 dataset
dataObject组件数据,包括内部数据和属性值
propertiesObject组件数据,包括内部数据和属性值(与 data 一致)

方法

方法名参数描述
setDataObject newData设置 data 并执行视图层渲染
triggerEventString name, Object detail, Object options触发事件,参见 组件间通信与事件
createSelectorQuery创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内
createIntersectionObserver创建一个 ​​​​​​​IntersectionObserver 对象,选择器选取范围为这个组件实例内
selectComponentString selector使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象
selectAllComponentsString selector使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组
selectOwnerComponent选取当前组件节点所在的组件实例(即组件的引用者),返回它的组件实例对象
getRelationNodesString relationKey获取这个关系所对应的所有关联节点,参见组件间关系

 

options

可声明自定义组件的渲染行为及数据交互等。

属性类型必填描述
pureDataPatternregexp纯数据字段是一些不用于界面渲染的 data 字段,可以用于提升页面更新性能。
styleIsolationstring组件样式隔离配置,可声明当前组件样式的渲染方式。
multipleSlotsboolean启动组件定义多 slot 特性。
addGlobalClassboolean添加全局样式,等同于 styleIsolation=apply-shared 优先级低于 styleIsolation 配置

styleIsolation 组件样式隔离

从基础库版本 2.0.0 开始支持。它支持以下取值:

  • isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);
  • apply-shared 表示页面 css 样式将影响到自定义组件,但自定义组件 css 中指定的样式不会影响页面;
  • shared 表示页面 css 样式将影响到自定义组件,自定义组件 css 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)

 

properties

声明自定义组件的属性配置及数据处理,每一个键值代表一个属性名,使用驼峰写法,通过 type 定义属性值的类型:String Number Boolean Object Array 其一,也可以为 null 表示不限制类型。value 可声明默认值,不设置则值为 null,并可通过 observer() 监听属性值的变化。

Component({
  properties: {
    myName: {
      type: String,
      value: 'smart',
      observer(newValue, oldValue) {
        // do something
      },
    },
  },
});

注意:在 properties 定义段中,属性名采用驼峰写法(myName);在 tyml 中,指定属性值时则对应使用连字符写法(<tag-name my-name="smart" />)。

tips

多数情况下,属性最好指定一个确切的类型。这样,在 tyml 中以字面量指定属性值时,值可以获得一个确切的类型,如:

<custom-comp min="1" max="5" />

此时,由于自定义组件的对应属性被规定为 Number 类型, min 和 max 会被赋值为 1 和 5 ,而非 "1" 和 "5" ,即:

this.data.min === 1; // true
this.data.max === 5; // true

observers

数据监听器可以用于监听和响应任何属性(properties)和数据 (data)字段的变化。通过定义以属性名、数据名、通配符 * 的函数处理响应。

Component({
  observers: {
    'value1, value2': function (value1, value2) {
      // this.setData 对应数据时触发
    },
    'some.subfield': function (subfield) {
      // 使用 setData 设置 this.data.some.subfield 时触发
      // (除此以外,使用 setData 设置 this.data.some 也会触发)
      subfield === this.data.some.subfield;
    },
    'arr[12]': function (arr12) {
      // 使用 setData 设置 this.data.arr[12] 时触发
      // (除此以外,使用 setData 设置 this.data.arr 也会触发)
      arr12 === this.data.arr[12];
    },
    'some.field.**': function (field) {
      // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
      // (除此以外,使用 setData 设置 this.data.some 也会触发)
      field === this.data.some.field;
    },
    '**': function () {
      // 每次 setData 都触发
    },
  },
});

注意事项

  • 数据监听器监听的是 setData 涉及到的数据字段,即使这些数据字段的值没有发生变化,数据监听器依然会被触发。
  • 如果在数据监听器函数中使用 setData 设置本身监听的数据字段,可能会导致死循环,需要特别留意。
  • 数据监听器和属性的 properties.field.observer 相比,数据监听器更强大且通常具有更好的性能。

 

data

自定义组件的数据对象和 properties 一同用于组件模板的渲染。

Component({
  properties: {
    name: {
      type: String,
      value: 'smart',
    },
  },
  data: { age: 18 },
});
<view>{{name}}: {{age}}</view>

methods

自定义组件的逻辑交互行为,结合组件实例方法实现响应用户操作、数据变更、事件通信等,在函数内通过 this 可访问组件实例。

Component({
  methods: {
    say() {
      this.setData({ name: 'hello world' });
    },
  },
});

lifetimes

自定义组件的生命周期,可用于响应事件处理。

生命周期参数描述
created在组件实例刚刚被创建时执行
attached在组件实例进入页面节点树时执行
ready在组件在视图层布局完成后执行, 节点的查找应在此阶段执行
moved在组件实例被移动到节点树另一个位置时执行
detached在组件实例被从页面节点树移除时执行
errorObject Error每当组件方法抛出错误时执行
Component({
  lifetimes: {
    attached() {
      // Do something when attached
    },
    ready() {
      // Do something when ready
    },
  },
});

pageLifetimes

自定义组件所在页面的生命周期声明对象,可用于响应事件处理。

生命周期参数描述
show组件所在的页面被展示时执行
hide组件所在的页面被隐藏时执行
resize组件所在的页面尺寸变化时执行2.6.2

 

externalClasses

组件接受的外部样式类,参见 外部样式类

 

relations

组件间关系,定义和使用组件间关系。

// path/to/custom-ul.js
Component({
  relations: {
    './custom-li': {
      type: 'child', // 关联的目标节点应为子节点
      linked(target) {
        // 每次有 custom-li 被插入时执行,target 是该节点实例对象,触发在该节点 attached 生命周期之后
      },
      linkChanged(target) {
        // 每次有 custom-li 被移动后执行,target 是该节点实例对象,触发在该节点 moved 生命周期之后
      },
      unlinked(target) {
        // 每次有 custom-li 被移除时执行,target 是该节点实例对象,触发在该节点 detached 生命周期之后
      },
    },
  },
});
// path/to/custom-li.js
Component({
  relations: {
    './custom-ul': {
      type: 'parent', // 关联的目标节点应为父节点
      linked(target) {
        // 每次被插入到 custom-ul 时执行,target 是 custom-ul 节点实例对象,触发在attached生命周期之后
      },
      linkChanged(target) {
        // 每次被移动后执行,target 是 custom-ul 节点实例对象,触发在moved生命周期之后
      },
      unlinked(target) {
        // 每次被移除时执行,target 是 custom-ul 节点实例对象,触发在detached生命周期之后
      },
    },
  },
});
// 注意:必须在两个组件定义中都加入relations定义,否则不会生效。

 

relations 定义段

relations 定义段包含目标组件路径及其对应选项,可包含的选项见下表。

选项类型是否必填描述
typeString目标组件的相对关系,可选的值为 parent 、 child 、 ancestor 、 descendant
linkedFunction关系生命周期函数,当关系被建立在页面节点树中时触发,触发时机在组件 attached 生命周期之后
linkChangedFunction关系生命周期函数,当关系在页面节点树中发生改变时触发,触发时机在组件 moved 生命周期之后
unlinkedFunction关系生命周期函数,当关系脱离页面节点树时触发,触发时机在组件 detached 生命周期之后
targetString如果这一项被设置,则它表示关联的目标节点所应具有的 behavior,所有拥有这一 behavior 的组件节点都会被关联

 

behaviors

用于自定义组件间代码共享的特性,类似于一些编程语言中的 mixins 或 traits。每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior behavior 也可以引用其它 behavior 。

 

在组件中使用

组件引用时,在 behaviors 定义段中将它们逐个列出即可。

// my-behavior.js
export default Behavior({
  behaviors: [
    /* 可引用其他 behavior */
  ],
  properties: { myBehaviorProperty: { type: String } },
  data: { myBehaviorData: {} },
  lifetimes: { attached() {} },
  methods: { myBehaviorMethod() {} },
});
import myBehavior  from '/my-behavior';
 
Component({
  behaviors: [myBehavior],
});

 

同名字段的覆盖和组合规则

组件和它引用的 behavior 中可以包含同名的字段,对这些字段的处理方法如下:

  • 如果有同名的属性 (properties) 或方法 (methods):
  1. 若组件本身有这个属性或方法,则组件的属性或方法会覆盖 behavior 中的同名属性或方法;
  2. 若组件本身无这个属性或方法,则在组件的 behaviors 字段中定义靠后的 behavior 的属性或方法会覆盖靠前的同名属性或方法;
  3. 在 2 的基础上,若存在嵌套引用 behavior 的情况,则规则为:父 behavior 覆盖 子 behavior 中的同名属性或方法。
  • 如果有同名的数据字段 (data):

    • 若同名的数据字段都是对象类型,会进行对象合并;
    • 其余情况会进行数据覆盖,覆盖规则为:组件 > 父 behavior > 子 behavior 、 靠后的 behavior > 靠前的 behavior。(优先级高的覆盖优先级低的,最大的为优先级最高)
  • 生命周期函数不会相互覆盖,而是在对应触发时机被逐个调用:

    • 对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序;
    • 对于同种生命周期函数,遵循如下规则:
      • behavior 优先于组件执行;
      • 子 behavior 优先于 父 behavior 执行;
      • 靠前的 behavior 优先于 靠后的 behavior 执行;
    • 如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数只会被执行一次。

 

definitionFilter

定义段过滤器,用于自定义组件扩展。

// behavior.js
export default Behavior({
  definitionFilter(defFields) {
    defFields.data.from = 'behavior';
  },
});
 
// component.js
import myBehavior from './behavior.js'
Component({
  data: {
    from: 'component',
  },
  behaviors: [myBehavior],
  ready() {
    console.log(this.data.from); // 此处会发现输出 behavior 而不是 component
  },
});

通过例子可以发现,自定义组件的扩展其实就是提供了修改自定义组件定义段的能力,上述例子就是修改了自定义组件中的 data 定义段里的内容。

 

高级进阶

组件间通信与事件

组件间的基本通信方式有以下几种。

  • TYML 数据绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容数据。
  • 事件:用于子组件向父组件传递数据,可以传递任意数据。
  • 如果以上两种方式不足以满足需要,父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。
监听事件

事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。

监听自定义组件事件的方法与监听基础组件事件的方法完全一致:

示例代码:

<!-- 当自定义组件触发 myevent 事件时,调用“onMyEvent”方法 -->
<component-tag-name bind:myevent="onMyEvent" />
Page({
  onMyEvent(event) {
    event.detail; // 自定义组件触发事件时提供的detail对象
  },
});
触发事件

自定义组件触发事件时,需要使用 triggerEvent 方法,指定事件名、detail 对象和事件选项:

示例代码:

<!-- 在自定义组件中 -->
<button bind:tap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
  properties: {},
  methods: {
    onTap() {
      var myEventDetail = {}; // detail对象,提供给事件监听函数
      this.triggerEvent('myevent', myEventDetail);
    },
  },
});

组件模板的 slot

在组件的 tyml 中可以包含 slot 节点,用于承载组件使用者提供的 tyml 结构

一个组件的 tyml 中支持有一个 slot 或者多个 slot(需启用 multipleSlots: true

在组件的 tyml 中使用多个 slot 时,以不同的 name 来区分。

<!-- 组件模板 -->
<view class="wrapper">
  <slot name="before"></slot>
  <view>这里是组件的内部细节</view>
  <slot name="after"></slot>
</view>

使用时,用 slot 属性来将节点插入到不同的 slot 上。

<!-- 引用组件的页面模板 -->
<view>
  <component-tag-name>
    <!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
    <view slot="before">这里是插入到组件slot name="before"中的内容</view>
    <!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
    <view slot="after">这里是插入到组件slot name="after"中的内容</view>
  </component-tag-name>
</view>

组件数据中的纯数据字段

有些情况下,某些 data 中的字段(包括 setData 设置的字段)既不会展示在界面上,也不会传递给其他组件,仅仅在当前组件内部使用。

此时,可以指定这样的数据字段为“纯数据字段”,它们将仅仅被记录在 this.data中,而不参与任何界面渲染过程,这样有助于提升页面更新性能。

指定“纯数据字段”的方法是在 Component 构造器的 options 定义段中指定 pureDataPattern 为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。

示例代码:

Component({
  options: {
    pureDataPattern: /^_/, // 指定所有 _ 开头的数据字段为纯数据字段
  },
  data: {
    a: true, // 普通数据字段
    _b: true, // 纯数据字段
  },
  methods: {
    myMethod() {
      this.data._b; // 纯数据字段可以在 this.data 中获取
      this.setData({
        c: true, // 普通数据字段
        _d: true, // 纯数据字段
      });
    },
  },
});

上述组件中的纯数据字段不会被应用到 TYML 上:

<view ty:if="{{a}}"> 这行会被展示 </view>
<view ty:if="{{_b}}"> 这行不会被展示 </view>
组件属性中的纯数据字段

属性也可以被指定为纯数据字段(遵循 pureDataPattern 的正则表达式)。

属性中的纯数据字段可以像普通属性一样接收外部传入的属性值,但不能将它直接用于组件自身的 TYML 中。

示例代码:

Component({
  options: {
    pureDataPattern: /^_/,
  },
  properties: {
    a: Boolean,
    _b: {
      type: Boolean,
      observer() {
        // 不要这样做!这个 observer 永远不会被触发
      },
    },
  },
});

注意:属性中的纯数据字段的属性 observer 永远不会触发!如果想要监听属性值变化,使用 数据监听器 代替。

使用数据监听器监听纯数据字段

数据监听器可以用于监听纯数据字段(与普通数据字段一样)。这样,可以通过监听、响应纯数据字段的变化来改变界面。

下面的示例是一个将 JavaScript 时间戳转换为可读时间的自定义组件。

Component({
  options: {
    pureDataPattern: /^timestamp$/, // 将 timestamp 属性指定为纯数据字段
  },
  properties: {
    timestamp: Number,
  },
  observers: {
    timestamp() {
      // timestamp 被设置时,将它展示为可读时间字符串
      var timeString = new Date(this.data.timestamp).toLocaleString();
      this.setData({
        timeString: timeString,
      });
    },
  },
});
<view>{{timeString}}</view>
  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IoT砖家涂拉拉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值