评论

让小程序页面和自定义组件支持 computed 和 watch 数据监听器

习惯于 VUE 或其他一些框架的同学们可能会经常使用它们的 computed 和 watch 。我们做了一个 npm 模块来提供 computed 和 watch 功能。

习惯于 VUE 或其他一些框架的同学们可能会经常使用它们的 computedwatch

小程序框架本身并没有提供这个功能,但我们基于现有的特性,做了一个 npm 模块来提供 computedwatch 功能。

先来个 GitHub 链接:https://github.com/wechat-miniprogram/computed

如何使用?

安装 npm 模块

npm install --save miniprogram-computed

示例代码

const computedBehavior = require('miniprogram-computed')

Component({
  behaviors: [computedBehavior],
  data: {
    a: 1,
    b: 1,
  },
  computed: {
    sum(data) {
      return data.a + data.b
    },
  },
})
const computedBehavior = require('miniprogram-computed')

Component({
  behaviors: [computedBehavior],
  data: {
    a: 1,
    b: 1,
    sum: 2,
  },
  watch: {
    'a, b': function(a, b) {
      this.setData({
        sum: a + b
      })
    },
  },
})

怎么在页面中使用?

其实上面的示例不仅在自定义组件中可以使用,在页面中也是可以的——因为小程序的页面也可用 Component 构造器来创建!

如果你已经有一个这样的页面:

Page({
  data: {
    a: 1,
    b: 1,
  },
  onLoad: function() { /* ... */ },
  myMethod1: function() { /* ... */ },
  myMethod2: function() { /* ... */ },
})

可以先把它改成:

Component({
  data: {
    a: 1,
    b: 1,
  },
  methods: {
    onLoad: function() { /* ... */ },
    myMethod1: function() { /* ... */ },
    myMethod2: function() { /* ... */ },
  },
})

然后就可以用了:

const computedBehavior = require('miniprogram-computed')

Component({
  behaviors: [computedBehavior],
  data: {
    a: 1,
    b: 1,
  },
  computed: {
    sum(data) {
      return data.a + data.b
    },
  },
  methods: {
    onLoad: function() { /* ... */ },
    myMethod1: function() { /* ... */ },
    myMethod2: function() { /* ... */ },
  },
})

应该使用 computed 还是 watch

看起来 computedwatch 具有类似的功能,应该使用哪个呢?

一个简单的原则: computed 只有 data 可以访问,不能访问组件的 methods (但可以访问组件外的通用函数)。如果满足这个需要,使用 computed ,否则使用 watch

想知道原理?

computedwatch 主要基于两个自定义组件特性: 数据监听器自定义组件扩展 。其中,数据监听器 observers 可以用来监听数据被 setData 操作。

  • 对于 computed ,每次执行 computed 函数时,记录下有哪些 data 中的字段被依赖。如果下一次 setData 后这些字段被改变了,就重新执行这个 computed 函数。
  • 对于 watch ,它和 observers 的区别不大。区别在于,如果一个 data 中的字段被设置但未被改变,普通的 observers 会触发,但 watch 不会。

如果遇到问题或者有好的建议,可以在 GitHub 提 issue 。

最后一次编辑于  2019-07-24  
点赞 12
收藏
评论

9 个评论

  • 2019-07-26

    为什么就不能让page也支持observers,把page写成component很怪啊。

    2019-07-26
    赞同 3
    回复 12
    • LastLeaf
      LastLeaf
      2019-07-26
      因为 Page({ ... }) 里面是可以有自由字段的,加定义段的话怕和已有小程序的代码冲突。
      2019-07-26
      回复
    • 2019-07-29
      。。。那以后如果又添加了一些新特性,总归是需要把一些函数名作为内部保留
      2019-07-29
      回复
    • LastLeaf
      LastLeaf
      2019-07-29回复
      所以 Component 构造器的第一级都是有限的字段名,比如 data methods 。
      2019-07-29
      回复
    • 2019-07-29回复LastLeaf
      所以为什么page不采取component构造器写发,自定义函数都必须写在methods下。第一级字段的都是内部自保留的函数
      2019-07-29
      1
      回复
    • LastLeaf
      LastLeaf
      2019-07-30回复
      历史原因了……
      2019-07-30
      1
      回复
    查看更多(7)
  • 陈式坚
    陈式坚
    2019-07-25

    我现在已经回到手动时代了,即不用watch和computed,全部是手动去调用函数更新。

    因为不太想过度依赖小程序框架的特性,迁移成本高且开发思维模式也不同


    也曾经通过setter getter去实现。但是setData是异步这件事情导致很混乱,也不用了

    2019-07-25
    赞同 2
    回复 1
    • LastLeaf
      LastLeaf
      2019-07-25
      setData 对于 this.data 的改变是同步的。用 getter / setter 的问题在于 this.data 是框架在维护的,很难处理。你可以参考一下这里 computed 的实现方式。
      2019-07-25
      2
      回复
  • 今夕何夕
    今夕何夕
    2023-08-24

    怎么监听对象数组内的属性是否变化

    2023-08-24
    赞同 1
    回复
  • 许
    2022-02-27

    插件引入需要加上.behavior 不然会报错!

    const computedBehavior = require('miniprogram-computed').behavior  // 注意: 需要加上.behavior才好使
    
    Component({
      behaviors: [computedBehavior],
      data: {
        a: 1,
        b: 1,
      },
      computed: {
        sum(data) {
          return data.a + data.b
        },
      },
    })
    
    2022-02-27
    赞同
    回复
  • 苏九
    苏九
    2021-08-19

    太难了。

    2021-08-19
    赞同
    回复
  • 辣油甩放
    辣油甩放
    2020-07-29

    对于重写了Page函数的是不是就没法用了?

    2020-07-29
    赞同
    回复 3
    • LastLeaf
      LastLeaf
      2020-07-30
      取决于你的 page 函数是怎么重写的。
      2020-07-30
      回复
    • 辣油甩放
      辣油甩放
      2020-07-30回复LastLeaf
      增加了几个通用function,注入了一些常用的data,我已经用重写Page的方法把Component也重写了一遍
      2020-07-30
      回复
    • LastLeaf
      LastLeaf
      2020-07-30回复辣油甩放
      如果正常将配置字段传递给 Page() / Component() ,应该是可以工作的。
      2020-07-30
      回复
  • 木 灬 可可
    木 灬 可可
    2020-01-06

    const computedBehavior = require('miniprogram-computed' )

    计算不了 import { storeBindingsBehavior, createStoreBindings } from'mobx-miniprogram-bindings'

    mobx 里面的值

    就是 你们官方 出的这两个插件 怎么配合

    使用


    下面的 identity 是mobx 的 可是在计算属性里面 找不到


    import { storeBindingsBehavior } from'mobx-miniprogram-bindings'

    const computedBehavior = require('miniprogram-computed'

    const app = getApp()


    Component({

    behaviors: [storeBindingsBehavior, computedBehavior],

    properties: {

    current: {

    type: String

    value: 'tabBarIndex'

    },

    },

    storeBindings: {

    store: app.store,

    fields: {

    identity: 'identity'

    },

    },

    computed: {

    // showList: {

    // require: ["$state", 'identity'],

    // fn({ $state, identity }) {

    // let arr = [

    // ['bPostAdmin', 'tabBarTaskAdmin','tabBarMessage', 'tabBarMy'],

    // ['tabBarIndex', 'tabBarDoTask', 'tabBarMessage', 'tabBarMy'],

    // ][typeof identity !== 'undefined' ? identity - 1 : 1] || []


    // return $state.tabBarList.filter(item => arr.includes(item.url))

    // }

    // },

    showList (data) {

    let { $state, identity } = data

    let arr = [

    ['bPostAdmin', 'tabBarTaskAdmin', 'tabBarMessage', 'tabBarMy'],

    ['tabBarIndex', 'tabBarDoTask', 'tabBarMessage', 'tabBarMy'],

    ][typeof identity !== 'undefined' ? identity - : ] || []


    return $state.tabBarList.filter(item => arr.includes(item.url))

    },


    },

    data: {

    },

    methods: {

    onChange(e) {

    this.$_yp_goPage(e.detail)

    },

    }

    })



    2020-01-06
    赞同
    回复 1
    • LastLeaf
      LastLeaf
      2020-01-06
      粗略看了一下你的代码,应该没啥问题。但是需要注意,identity 一开始可能是 undefined ,这时候 showList 会用 identity === undefined 来计算一次,之后 identity 值存在之后会再次重新计算 showList 。
      2020-01-06
      回复
  • 太阳🌙粑粑
    太阳🌙粑粑
    2019-12-16


    报这个错不知道为啥

    2019-12-16
    赞同
    回复 7
    • 太阳🌙粑粑
      太阳🌙粑粑
      2019-12-16
      我就是npm下来直接用了 没修改什么 看教程也没啥修改
      2019-12-16
      回复
    • LastLeaf
      LastLeaf
      2019-12-17回复太阳🌙粑粑
      看起来是依赖模块缺失了。看下 node_modules 里面是不是有 rfdc ?
      2019-12-17
      回复
    • 太阳🌙粑粑
      太阳🌙粑粑
      2019-12-17回复LastLeaf
      没有
      2019-12-17
      回复
    • LastLeaf
      LastLeaf
      2019-12-17回复太阳🌙粑粑
      npm install 正常吗?
      2019-12-17
      回复
    • PoleSwify
      PoleSwify
      2020-03-27回复LastLeaf
      我node_modules有rfdc 但是是报miniprogram-computed is not defined
      2020-03-27
      回复
    查看更多(2)
  • 云天团
    云天团
    2019-11-27

    请问一下,computed 可以依赖 computed 里面的数据吗?

    会不会影响性能呢?

    2019-11-27
    赞同
    回复 2
    • 云天团
      云天团
      2019-11-27
      跑了一下是支持的,感谢官方适配
      2019-11-27
      回复
    • LastLeaf
      LastLeaf
      2019-11-27
      v2 版本以上可以支持。 computed 不可避免会对性能有一定影响,不过现在看起来影响比较小。 watch 不会有什么影响。
      2019-11-27
      回复
登录 后发表内容