# Custom component extensions
To better customize the functionality of a custom component, you can use the custom component extension mechanism.Support starts with Weixin Mini Program base library version {% version ('2.2.3')%}.
# The effect of the extension
To get a better understanding of the effect of scaling up, let me give you an example:
// behavior.js
module.exports = Behavior({
definitionFilter(defFields) {
defFields.data.from = 'behavior'
},
})
// component.js
Component({
data: {
from: 'component'
},
behaviors: [require('behavior.js')],
ready() {
console.log(this.data.from) // 此处会发现输出 behavior 而不是 component
}
})
As can be seen from examples, custom component extension provides the ability to modify a custom component definition segment, such as modifying the contents of thedatadefinition segment in a custom components.
# Use of extensions
The behavior ()constructor provides a new definition segmentdefinitionFilterto support custom component extensions.definitionFilterIt is a function that injects two parameters when called. The first parameter is a definition object using the component / behavior of the behavior, and the second parameter is thedefinitionFilterlist of functions for the behavior used by the behavior.
The following is an example to illustrate:
// behavior3.js
module.exports = Behavior({
definitionFilter(defFields, definitionFilterArr) {},
})
// behavior2.js
module.exports = Behavior({
behaviors: [require('behavior3.js')],
definitionFilter(defFields, definitionFilterArr) {
// definitionFilterArr[0](defFields)
},
})
// behavior1.js
module.exports = Behavior({
behaviors: [require('behavior2.js')],
definitionFilter(defFields, definitionFilterArr) {},
})
// component.js
Component({
behaviors: [require('behavior1.js')],
})
The above code declares a custom component and three behaviors, each using thedefinitionFilterdefinition segment.Then, in the order of declarations, the following things will happen:
- The
definitionFilterof behavior3 is called when a behavior2 declaration is madeFunctions where thedefFieldsparameter is the definition segment of behavior 2, and thedefinitionFilterArrparameter becomes an empty array because behavior 3 does not use another behavior. - The
definitionFilterof behavior2 is called when the declaration of behavior1 is madeFunction wheredefFieldsparameters are the definition segment of behavior1,definitionFilterArrarguments are an array of 1 length,definitionFiltersArr[0]is thedefinitionFilterfunction of behavior3 because behavior2 uses behavior3.Here, the user can decide whether to call thedefinitionFilterfunction of behavior3 when making a declaration of behavior1, and if so, supplement the code here.definitionFilterArr [0](defFields)ThedefinitionFilterArrparameter is passed in from the base library complement. - Similarly, the
definitionFilterfunction of behavior1 is called when making a component declaration.
In a nutshell, thedefinitionFilter]]function can be understood as when A uses B, A declares that B'sdefinitionfilter]]function is called and passes into A's definition object for B to filter.At this point, if B also uses C and D, then B can decide whether to call thedefinitionFilterfunctions of C and D to filter the defined objects of A.
Code example:
# A real case.
The computational properties of custom components can be easily implemented using extensions:
// 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
}
})
Use in components:
const beh = require('./behavior.js')
Component({
behaviors: [beh],
data: {
a: 0,
},
computed: {
b() {
return this.data.a + 100
},
},
methods: {
onTap() {
this.setData({
a: ++this.data.a,
})
}
}
})
<view>data: {{a}}</view>
<view>computed: {{b}}</view>
<button bindtap="onTap">click</button>
The implementation principle is very simple, the existing setData for secondary packaging, in each setData when calculating the value of each field computed, and then set to data, in order to achieve the effect of calculating properties.
This implementation is presented as a simple example and should not be used directly in a production environment.