微信小程序自定义组件

一.组件模板

1、组件模版

组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。

在组件模板中可以提供一个 <slot> 节点,用于承载组件引用时提供的子节点。

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

2、模板数据绑定

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

组件页面

Js设置

properties: {
  propA: String
}

wxml页面调用

{{propA}}

3、组件wxml的slot

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

默认情况下,一个组件的wxml中只能有一个slot。需要使用多slot时,可以在组件js中声明启用。

Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: { /* ... */ },
  methods: { /* ... */ }
})

此时,可以在这个组件的wxml中使用多个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>

二.组件样式

组件对应 wxss 文件的样式,只对组件wxml内的节点生效。编写组件样式时,需要注意以下几点:

  • 组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,请改用class选择器。
  • 组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。
  • 子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。
  • 继承样式,如 font 、 color ,会从组件外继承到组件内。
  • 除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效。

1、外部样式类

/* 组件 custom-component.js */

Component({
  externalClasses: ['my-class']
})

<!– 组件 custom-component.wxml –>

<custom-component class="my-class">

  这段文本的颜色由组件外的 class 决定</custom-component>

2、使组件接受全局样式

/* 组件 custom-component.js */

Component({
  options: {
    addGlobalClass: true,
  }
})

<!– 组件 custom-component.wxml –>

<text class="red-text">

  这段文本的颜色由 `app.wxss` 和页面 `wxss` 中的样式定义来决定</text>

三.Component构造器

1、 定义段

定义段类型是否必填描述最低版本
propertiesObject Map组件的对外属性,是属性名到属性设置的映射表,属性设置中可包含三个字段, type表示属性类型、 value 表示属性初始值、 observer 表示属性值被更改时的响应函数 
dataObject组件的内部数据,和 properties 一同用于组件的模板渲染 
observersObject组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器2.6.1
methodsObject组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件事件 
behaviorsString Array类似于mixins和traits的组件间代码复用机制,参见 behaviors 
createdFunction组件生命周期函数,在组件实例刚刚被创建时执行,注意此时不能调用 setData ,参见 组件生命周期 
attachedFunction组件生命周期函数,在组件实例进入页面节点树时执行,参见 组件生命周期 
readyFunction组件生命周期函数,在组件布局完成后执行,参见 组件生命周期 
movedFunction组件生命周期函数,在组件实例被移动到节点树另一个位置时执行,参见 组件生命周期 
detachedFunction组件生命周期函数,在组件实例被从页面节点树移除时执行,参见 组件生命周期 
relationsObject组件间关系定义,参见 组件间关系 
externalClassesString Array组件接受的外部样式类,参见 外部样式类 
optionsObject Map一些选项(文档中介绍相关特性时会涉及具体的选项设置,这里暂不列举) 
lifetimesObject组件生命周期声明对象,参见 组件生命周期2.2.3
pageLifetimesObject组件所在页面的生命周期声明对象,支持页面的 show 、 hide 等生命周期,参见 组件生命周期2.2.3
definitionFilterFunction定义段过滤器,用于自定义组件扩展,参见 自定义组件扩展2.2.3

2、 属性

属性名类型描述
isString组件的文件路径
idString节点id
datasetString节点dataset
dataObject组件数据,包括内部数据和属性值
propertiesObject组件数据,包括内部数据和属性值(与 data 一致)
方法名参数描述
setDataObject newData设置data并执行视图层渲染
hasBehaviorObject behavior检查组件是否具有 behavior (检查时会递归检查被直接或间接引入的所有behavior)
triggerEventString name, Object detail, Object options触发事件,参见 组件事件
createSelectorQuery 创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内
createIntersectionObserver 创建一个 IntersectionObserver 对象,选择器选取范围为这个组件实例内
selectComponentString selector使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象(会被 wx://component-export 影响)
selectAllComponentsString selector使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组
getRelationNodesString relationKey获取这个关系所对应的所有关联节点,参见 组件间关系
groupSetDataFunction callback立刻执行 callback ,其中的多个 setData 之间不会触发界面绘制(只有某些特殊场景中需要,如用于在不同组件同时 setData 时进行界面绘制同步)
getTabBar返回当前页面的 custom-tab-bar 的组件实例,详见自定义 tabBar

3、 方法

方法名参数描述
setDataObject newData设置data并执行视图层渲染
hasBehaviorObject behavior检查组件是否具有 behavior (检查时会递归检查被直接或间接引入的所有behavior)
triggerEventString name, Object detail, Object options触发事件,参见 组件事件
createSelectorQuery 创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内
createIntersectionObserver 创建一个 IntersectionObserver 对象,选择器选取范围为这个组件实例内
selectComponentString selector使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象(会被 wx://component-export 影响)
selectAllComponentsString selector使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组
getRelationNodesString relationKey获取这个关系所对应的所有关联节点,参见 组件间关系
groupSetDataFunction callback立刻执行 callback ,其中的多个 setData 之间不会触发界面绘制(只有某些特殊场景中需要,如用于在不同组件同时 setData 时进行界面绘制同步)
getTabBar返回当前页面的 custom-tab-bar 的组件实例,详见自定义 tabBar

注意:在 properties 定义段中,属性名采用驼峰写法(propertyName);在 wxml 中,指定属性值时则对应使用连字符写法(component-tag-name property-name=”attr value”),应用于数据绑定时采用驼峰写法(attr=”{{propertyName}}”)。

4、 构造页面

组件的属性可以用于接收页面的参数,如访问页面 /pages/index/index?paramA=123¶mB=xyz ,如果声明有属性 paramA 或 paramB ,则它们会被赋值为 123 或 xyz 。

页面的生命周期方法(即 on 开头的方法),应写在 methods 定义段中。

代码示例:

{
  "usingComponents": {}
}
Component({
  properties: {
    paramA: Number,
    paramB: String,
  },
  methods: {
    onLoad() {
      this.data.paramA // 页面参数 paramA 的值
      this.data.paramB // 页面参数 paramB 的值
    }
  }
})

五.组件间通信与事件

1、 组件间通信

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

  • WXML 数据绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容数据(自基础库版本 2.0.9 开始,还可以在数据中包含函数)。具体在 组件模板和样式 章节中介绍。
  • 事件:用于子组件向父组件传递数据,可以传递任意数据。
  • 如果以上两种方式不足以满足需要,父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。

2、 监听事件

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

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

代码示例:

<!– 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 –>

<component-tag-name bindmyevent="onMyEvent" />

<!– 或者可以写成 –>

<component-tag-name bind:myevent="onMyEvent" />
Page({
  onMyEvent(e) {
    e.detail // 自定义组件触发事件时提供的detail对象
  }
})

3、 触发事件

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

代码示例:

在开发者工具中预览效果

<!– 在自定义组件中 –>

<button bindtap=”onTap”>点击这个按钮将触发“myevent”事件</button>

Component({
  properties: {},
  methods: {
    onTap() {
      const myEventDetail = {} // detail对象,提供给事件监听函数
      const myEventOption = {} // 触发事件的选项
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})

4、 组件间使用数据监听器

有时,在一些数据字段被 setData 设置时,需要执行一些操作。

例如, this.data.sum 永远是 this.data.numberA 与 this.data.numberB 的和。此时,可以使用数据监听器进行如下实现。

Component({
  attached() {
    this.setData({
      numberA: 1,
      numberB: 2,
    })
  },
  observers: {
    'numberA, numberB': function (numberA, numberB) {
    // 在 numberA 或者 numberB 被设置时,执行这个函数
      this.setData({
        sum: numberA + numberB
      })
    }
  }
})

五.组件生命周期

1、 组件的主要生命周期

2、 组件所在页面的生命周期

六.组件间关系

Relations

抽象节点