扩展小程序页面compute属性思路
发布于 3 年前 作者 jiaqiang 3771 次浏览 来自 分享

本来之前技术栈一直是Vue,后来做小程序了,各种不习惯,尤其是少了计算属性和监听器,wxml里面又不能直接放函数,又没有Vue那种过滤器的写法。也许有人说直接uni-app就好了,但是平时做跨端的很少,所以我偏不用uni-app,我就要自己写一个。以下内容纯靠个人臆想,搞出来的compute属性虽然能用,但仅供参考。

出于偶然发现了小程序能够自己重写生命周期钩子,听说很多的一些统计sdk也都是利用这样的机制做事件打点统计啥的,于是这么好玩的东西,我决定参一脚试一下好不好玩。compute属性的扩展就是在重写的生命周期里面做的,实现思路步骤大体如下两步:

  1. 在重写小程序onLoad生命周期里面判断一下用户是否有定义compute属性,如果有的话深拷贝一个data出来给这个data循环遍历绑定一下get用来做compute的依赖收集,然后用setData绑定到data上,compute属性里面的一般是个函数返回一个经过计算处理的值,这个函数里面一旦调用了data上的属性时就会触发前面设置的get函数进行依赖收集。
  2. 依赖收集完成后,还需要重写一下setData,监听一下用户在用setData改数据时都改了哪些数据,然后触发compute的更新。

OK,大功告成,一个勉强能跑的小轮子就出来了,其实小程序里面很多api都能重写或者使用defineProperty来监听,可以用来解决日常很多的开发问题,像啥页面栈溢出问题,随手加个watch监听器,加个store全局数据管理啥的估计都不是啥大问题。

最后附上代码和用法,仅提供一个思路,cv的话请慎重。

// app.js
require('./utils/compute.js') 
// page.js
Page({
  data: {
    a0,
    k: [0001],
    c: {
      a9
    }
  },
  compute: {
    b(data) {
      return data.c.a + data.a + data.k[0]
    }
  },
  onLoad() {
        // 下面几种写法都能监听到并更新
    this.setData({
      a8,
      'c.a'10,
      [`k[${0}]`]: 999
    }, () => {
      console.log(this.data.b)
    })
  },
})
// compute.js
const oldPage = Page
Page = function (app{
    let oldOnLoad = app.onLoad;
    app.onLoad = function (options{
        let o_setData = this.setData
        let dep = {}
                //  重写setData
        this.setData = function (o, fn{
            o_setData.call(this, o, function () {
                if (app.compute) {
                    Object.keys(dep).map(c => {
                        Object.keys(o).map(i => {
                            if (dep[c].includes(i) || dep[c].includes(i.split('.')[0]) || dep[c].includes(i.split('[')[0])) {
                                o_setData.call(this, {
                                    [c]: app.compute[c].call(thisthis.data)
                                })
                            }
                        })
                    })
                }
                fn && fn.call(this)
            })
        }
                //  收集一下依赖
        if (app.compute) {
            let _data = JSON.parse(JSON.stringify(this.data))
            let bufferDep = []
            Object.keys(_data).map(key => {
                let val = _data[key]
                Object.defineProperty(_data, key, {
                    getfunction () {
                        bufferDep.push(key)
                        return val
                    }
                })
            })
            Object.keys(app.compute).map(key => {
                bufferDep = []
                this.setData({
                    [key]: app.compute[key].call(this, _data)
                }, function () {
                    dep[key] = bufferDep
                })
            })
        }
        oldOnLoad.call(this, options)
    }
    return oldPage(app)
}
回到顶部