Vue之计算属性

示例:

<template>
  <div id="app">
    <div ref="msg">{{ name }}</div>
    <button @click="change">change</button>
    <button @click="changeLast">changeLast</button>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      firstName: 'Yi',
      lastName: 'Huang',
      useless: 0
    };
  },
  computed: {
    name() {
      if (this.useless > 0) {
        return this.firstName + ',' + this.lastName;
      }
      return 'please click change'
    }
  },
  methods: {
    change() {
      this.useless++;
    },
    changeLast() {
      this.lastName = 'Zhang';
    }
  }
}
</script>
  1. 首先在App组件render生成vnode过程中,会访问name,访问name就会执行到以下代码:|
    function createComputedGetter (key) {
      return function computedGetter () {
        const watcher = this._computedWatchers && this._computedWatchers[key]
        if (watcher) {
          if (watcher.dirty) {
            watcher.evaluate()
            // 这一步Dep.target是这个computed watcher,完成了依赖收集,然后因为执行了popTarget,Dep.target 变回了渲染watcher
          }
          if (Dep.target) {
            watcher.depend()
            // 这一步将刚才收集的依赖又添加到了渲染watcher中
          }
          return watcher.value
        }
      }
    }
  2. 这个函数中,首先执行watcher.evaluate,执行过程中会对(用户写入的computed里面的name方法进行求值),求值的过程中就会访问到this.useless的getter方法,执行getter方法进行依赖收集,此时订阅的依赖是由computed的watcher订阅的依赖,也就是computed的watcher去订阅this.useless的变化,当this.useless的值发生变化时,就会触发set之后执行dep.notify而执行computed watcher自身的update。
  3. 执行完后返回值:'please click change'。接着执行watcher.depend方法,这一步将刚刚computed收集到的依赖,又添加进渲染watcher中,这样当值发生变化时,就会同时触发computed的update和重新渲染。
  4. 当点击change按钮时,this.useless发生变化,触发set,调用dep.notify,遍历dep.subs中的两个wacher,一个是computed wathcer一个是渲染wacher,依次执行update方法,如下
     update () {
        /* istanbul ignore else */
        if (this.lazy) {
          this.dirty = true
        } else if (this.sync) {
          this.run()
        } else {
          queueWatcher(this)
        }
      }
  5. 第一次是把this.dirty置为true,因为它是计算属性的watcher。第二次直接执行queueWatcher进行渲染,在渲染的过程中又会进行重新求值,在求值的过程中又会触发get,收集新的依赖(包括firstName和lastName的依赖),作用是为了当他们两个的值发生变化时,会触发computed的update过程。最后执行页面的重新渲染。

 

在vue新版本中,只要修改了this.useless的值,不管计算属性最终返回什么值,都会进行重新渲染,而在旧版中会先判断值是否发生变化,如果计算属性返回的值没有变化,则不进行渲染。一句话说就是新版本:少计算,多渲染。旧版本:多计算,少渲染。

posted @ 2021-02-26 11:06  ltog  阅读(81)  评论(0编辑  收藏  举报