miniprogram-computed.js代码分析
小程序本身不提供类似于Vue的计算属性,在再加上其渲染ui与js执行分离的原因,感觉要模拟一个计算属性处理起来有些困难,好在官方提供了我们自定义拓展miniprogram-computed
然后下文是对其中代码的一些个人理解,笔记。
如何在小程序的代码中,书写类似Vue这种的计算属性?
computed: {
xxx() {
return yyy
}
}
没错,在小程序中也可以实现这种写法。就是通过其提供给我们的自定义组件功能:
Behavior(Object)
这个有点类似mixin,就是像注入式的在当前Component组件中执行自生的方法或者周期函数。通过
const computedBehavior = require('miniprogram-computed')
Component({
behaviors: [computedBehavior],
})
注入到当前组件中,注意是定义为Component的组件,在Page组件中并不能使用。
代码分析
个人感觉代码可以分为 2个部分去理解
初始化computed属性----重写setData函数
初始化computed属性
behavior构造器中有个definitionFilter(defFields)函数会先执行。函数就是通过defFields参数来获取当前组件的上下文,也就是可以获取到我们写的computed属性,然后遍历computed中对象的键值对,插入到data属性中,也就是说computed中的对象,最终在标签中都是通过{{xx}}绑定我们的data属性(PS.代码中还有一段处理properties属性的,这里没有讨论)
definitionFilter(defFields) {
const computed = defFields.computed || {}
const computedKeys = Object.keys(computed)
//...
const needUpdate = {}
const computedCache = scope._computedCache || scope.data // scope._computedCache 这里在生命周期声明
for (let i = 0, len = computedKeys.length; i < len; i++) {
const key = computedKeys[i]
const getter = computed[key]
if (typeof getter === 'function') {
const value = getter.call(scope)
if (computedCache[key] !== value) { // 如果不同 就是需要通过setData更新的对象
needUpdate[key] = value
computedCache[key] = value
}
}
}
return needUpdate
}
这个needUpdate就是我们需要手动更新的属性
重写setData函数
在生命周期用一个对象保存原生的setData方法,然后用另外一个_setData来覆盖setData方法,使得在操作setData时(其实调用的是我们绑定的_setData方法),能同时更新到原生的data以及我们写上的computed字段。
lifetimes: {
created() {
this._originalSetData = this.setData
this.setData = this._setData
},
},
definitionFilter(defFields) {
defFields.methods = defFields.methods || {}
defFields.methods._setData = function (data, callback) {}
}
代码的思想是当我通过setData(覆盖了的)方法来更改了某个属性值。函数首先会去遍历所有data属性,然后挑出非computed的data属性,然后直接调用原生的setData(this._originalSetData )来首先更新data属性。 然后再通过判断所有的计算属性中有哪些属性是原来值不同,然后再更新渲染相关计算属性。两次渲染有先后顺序,先更新data再更新计算属性。
definitionFilter(defFields) {
defFields.methods._setData = function (data, callback) {
const dataKeys = Object.keys(data)
for (let i = 0, len = dataKeys.length; i < len; i++) {
const key = dataKeys[i]
if (computed[key]) delete data[key]
}
// 做 data 属性的 setData
originalSetData.call(this, data, callback)
// 计算 computed
const needUpdate = calcComputed(this)
// 做 computed 属性的 setData
originalSetData.call(this, needUpdate)
}
}
后续
computed属性完成之后呢,下一步就是要自定义一个类似vuex的状态管理组件。网上的也有许多的版本,本人在老大的指导下去了解了一下redux以及mobx的状态管理机制。之后会继续与大家分享。
本人水平有限,有不对的地方,希望大家多多包涵。。。