一、Component组件的扩展
// 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 } })
通过例子可以发现,自定义组件的扩展其实就是提供了修改自定义组件定义段的能力,上述例子就是修改了自定义组件中的 data 定义段里的内容。
二、使用扩展
Behavior() 构造器提供了新的定义段 definitionFilter ,用于支持自定义组件扩展。 definitionFilter 是一个函数,在被调用时会注入两个参数,第一个参数是使用该 behavior 的 component/behavior 的定义对象,第二个参数是该 behavior 所使用的 behavior 的 definitionFilter 函数列表。
// 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')], })
三、案例解析
// 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 } })
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>
实现原理很简单,对已有的 setData 进行二次封装,在每次 setData 的时候计算出 computed 里各字段的值,然后设到 data 中,以达到计算属性的效果。