1.监听小程序组件的属性值变化
我们可以使用两种形式,一种是给observer直接定义一个函数,另一种是observer调用methods中的方法
此处不能使用箭头函数,否则this会报undefined
javascript
show: {
// 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
type: Boolean,
value: true,
observer: function(newVal,oldVal){
}
}
直接写methods中的方法名即可
javascript
show: {
// 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
type: Boolean,
value: true,
observer: '_showChange'
}
2.组件间通信
父组件可以通过this.selectComponent获取子组件的实例对象,这样可以直接访问子组件的任何数据和方法
3.behavior
用于组件间共享代码,类似于编程语言中的mixins。每个behavior可以包含一组属性、数据、方法和生命周期,组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期也会在对应的时机被调用。每个组件可以引用多个behavior,每个behavior也可以引用其他behavior
如果组件中存在同名的属性和方法,则组件的属性和方法会覆盖behavior中的属性和方法。靠后的behavior中的属性和方法,会覆盖靠前的behavior属性和方法。
生命周期函数:behavior会优先于组件执行,被引用的behavior会优先于引用的behavior执行。靠前的behavior会优先于靠后的behavior执行。
javascript
module.exports = Behavior({
behaviors: [],
properties: {
myBehaviorProperty: {
type: String
}
},
data: {
myBehaviorData: {}
},
attached: function(){},
methods: {
myBehaviorMethod: function(){}
}
})
4.监听组件属性值变化
observers,类似于vue中的watch
javascript
Component({
attached: function() {
this.setData({
numberA: 1,
numberB: 2,
})
},
observers: {
'numberA, numberB': function(numberA, numberB) {
// 在 numberA 或者 numberB 被设置时,执行这个函数
this.setData({
sum: numberA + numberB
})
}
}
})
5.组件间关系
在下面的案例中,custom-ui和custom-li都是自定义组件,他们之间有相互依赖关系,组件间通信往往很复杂,此时可以在组件定义时加入relations,可以解决这问题.
html
<custom-ul>
<custom-li> item 1 </custom-li>
<custom-li> item 2 </custom-li>
</custom-ul>
javascript
// path/to/custom-ul.js
Component({
relations: {
'./custom-li': {
type: 'child', // 关联的目标节点应为子节点
linked: function(target) {
// 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
},
linkChanged: function(target) {
// 每次有custom-li被移动后执行,target是该节点实例对象,触发在该节点moved生命周期之后
},
unlinked: function(target) {
// 每次有custom-li被移除时执行,target是该节点实例对象,触发在该节点detached生命周期之后
}
}
},
methods: {
_getAllLi: function(){
// 使用getRelationNodes可以获得nodes数组,包含所有已关联的custom-li,且是有序的
var nodes = this.getRelationNodes('path/to/custom-li')
}
},
ready: function(){
this._getAllLi()
}
})
javascript
// path/to/custom-li.js
Component({
relations: {
'./custom-ul': {
type: 'parent', // 关联的目标节点应为父节点
linked: function(target) {
// 每次被插入到custom-ul时执行,target是custom-ul节点实例对象,触发在attached生命周期之后
},
linkChanged: function(target) {
// 每次被移动后执行,target是custom-ul节点实例对象,触发在moved生命周期之后
},
unlinked: function(target) {
// 每次被移除时执行,target是custom-ul节点实例对象,触发在detached生命周期之后
}
}
}
})
6.纯数据字段
如果一些数据不用于界面渲染,可以把它设置成春数据字段。这样可以提供页面性能
指定纯数据字段的方法是在Component的options属性中,指定pureDataPattern为一个正则表达式,字段名符合这个正则表达式的字段,就是纯数据字段。纯数据字段不能参与页面渲染。
javascript
Component({
options: {
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
},
data: {
a: true, // 普通数据字段
_b: true, // 纯数据字段
},
methods: {
myMethod() {
this.data._b // 纯数据字段可以在 this.data 中获取
this.setData({
c: true, // 普通数据字段
_d: true, // 纯数据字段
})
}
}
})
属性也可以被指定为纯数据字段,同样,属性也不能参与wxml渲染。纯数据字段的属性的observer永远不会被触发,如果需要监听其变化,可以使用数据监听器
javascript
Component({
options: {
pureDataPattern: /^_/
},
properties: {
a: Boolean,
_b: {
type: Boolean,
observer() {
// 不要这样做!这个 observer 永远不会被触发
}
},
}
})
也可以在页面或者自定义组件的json中配置pureDataPattern,但此时的pureDataPattern是一个字符串,而不是正则表达式
javascript
{
"pureDataPattern": "^_"
}
7.抽象节点
有时候,自定义组件模板中的一些节点,其对应的自定义组件不是由自定义组件本身决定的,而是由自定义组件的调用者决定的,这时候可以把这个节点声明为抽象节点。
html
<!-- selectable-group.wxml -->
<view wx:for="{{labels}}">
<label>
<selectable disabled="{{false}}"></selectable>
{{item}}
</label>
</view>
其中,"selectable"不是任何在 json 文件的 usingComponents
字段中声明的组件,而是一个抽象节点。它需要在 componentGenerics
字段中声明。
json
{
"componentGenerics": {
"selectable": true
}
}
在使用 selectable-group 组件时,必须指定"selectable"具体是哪个组件:
ini
<selectable-group generic:selectable="custom-radio" />
这样,在生成这个 selectable-group 组件的实例时,"selectable"节点会生成"custom-radio"组件实例。这个custom-radio需要包含在组件json的usingComponents字段中。
json
{
"usingComponents": {
"custom-radio": "path/to/custom/radio",
"custom-checkbox": "path/to/custom/checkbox"
}
}
抽象节点可以指定一个默认组件,当具体组件未被指定时,将创建默认组件的实例。默认组件可以在 componentGenerics
字段中指定:
json
{
"componentGenerics": {
"selectable": {
"default": "path/to/default/component"
}
}
}
节点的 generic 引用 generic:xxx="yyy"
中,值 yyy
只能是静态值,不能包含数据绑定。因而抽象节点特性并不适用于动态决定节点名的场景
8.自定义组件扩展
behavior提供了新的自定义字段,definitionFilter用于支持自定义组件扩展。
案例:实现组件的computed属性
javascript
// behavior.js
module.exports = Behavior({
lifetimes: {
created() {
this._originalSetData = this.setData // 原始 setData
this.setData = this._setData // 封装后的 setData
}
},
definitionFilter(defFields) {
const computed = defFields.computed || {}
const computedKeys = Object.keys(computed)
const computedCache = {}
// 计算 computed
const calcComputed = (scope, insertToData) => {
const needUpdate = {}
const data = defFields.data = defFields.data || {}
for (let key of computedKeys) {
const value = computed[key].call(scope) // 计算新值
if (computedCache[key] !== value) needUpdate[key] = computedCache[key] = value
if (insertToData) data[key] = needUpdate[key] // 直接插入到 data 中,初始化时才需要的操作
}
return needUpdate
}
// 重写 setData 方法
defFields.methods = defFields.methods || {}
defFields.methods._setData = function (data, callback) {
const originalSetData = this._originalSetData // 原始 setData
originalSetData.call(this, data, callback) // 做 data 的 setData
const needUpdate = calcComputed(this) // 计算 computed
originalSetData.call(this, needUpdate) // 做 computed 的 setData
}
// 初始化 computed
calcComputed(defFields, true) // 计算 computed
}
})
9.占位组件
自定义组件所引用的其他自定义组件,在刚开始进行渲染时可能处于不可用的状态。此时,为了使渲染过程不被阻塞,可以说使用占位组件。
页面或自定义组件对应的 JSON 配置中的 componentPlaceholder
字段用于指定占位组件,如:
json
{
"usingComponents": {
"comp-a": "../comp/compA",
"comp-b": "../comp/compB",
"comp-c": "../comp/compC"
},
"componentPlaceholder": {
"comp-a": "view",
"comp-b": "comp-c"
}
}