Vue中的computed属性和nextTick方法

computed

computed属性的实现原理

  • Vue实例初始化时,给data的每个属性(dataKey)都添加getter和setter方法
  • 计算属性computed初始化时,提供的函数将作为对应属性(computedKey)的getter方法
    其中,computed属性采用函数式声明
 computedKey: function(){
        return this.dataKey+'change'
     }
  • 当首次获取计算属性的值是,dep开始收集依赖,即收集到dataKey和computedKey的依赖关系,也就是上面的this.datakey+'change';
    在dataKey变化时,此时会调用dataKey的getter方法,通过dep收集的依赖,可以判定出data与computed对应数据的依赖关系
    此时可以做到,在data发生变化时,computed属性数据也发生变化

computed属性的用法

目的:是为了避免模板中加入太多的计算公式,不够精炼,而且computed属性比较节约
官网中的写法:

Original message: "{{ message }}"

Computed reversed message: "{{ reversedMessage }}"

var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

在模板文件中,只需要在插值表达式中写reversedMessage这个属性即可,它与message有依赖关系

computed属性与watch的区别

  • 当需要数据在 异步变化或者开销较大时 ,执行更新,使用watch会更好一些;而computed不能进行异步操作
  • computed可以用 缓存中拿数据 ,而watch是每次都要运行函数计算,不管变量的值是否发生变化,而computed在值没有发生变化时,可以直接读取上次的值

computed属性与methods的区别

在模板文件中,computed属性只需要写reverseMessage,而methods需要写成reverseMessage(),最明显的区别就是methods是方法,需要执行;
computed属性只有在依赖的data放生变化时,才会重新执行,否则会使用缓存中的值,而methods是每次进入页面都要执行的,有些需要每次进入页面都执行的方法,需要使用methods,而computed属性比较节约。

this.$nextTick

nextTick的原理

nextTick 可以让我们在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM。
在 Vue 2.4 之前都是使用的 microtasks,但是 microtasks 的优先级过高,在某些情况下可能会出现比事件冒泡更快的情况,(也就是,出现微任务执行比点击事件之类的事件触发还要快,导致逻辑出错)但如果都使用 macrotasks 又可能会出现渲染的性能问题。所以在新版本中,会默认使用 microtasks,但在特殊情况下会使用 macrotasks,比如 v-on。

对于实现 macrotasks ,会先判断是否能使用 setImmediate ,不能的话降级为 MessageChannel ,以上都不行的话就使用setTimeout

nextTick的使用实例

//模板
{{msg}}
Message got outside $nextTick: {{msg1}}
Message got inside $nextTick: {{msg2}}
Message got outside $nextTick: {{msg3}}
//Vue实例
new Vue({
  el: '.app',
  data: {
    msg: 'Hello Vue.',
    msg1: '',
    msg2: '',
    msg3: ''
  },
  methods: {
    changeMsg() {
      this.msg = "Hello world."
      this.msg1 = this.$refs.msgDiv.innerHTML
      this.$nextTick(() => {
        this.msg2 = this.$refs.msgDiv.innerHTML
      })
      this.msg3 = this.$refs.msgDiv.innerHTML
    }
  }
})

点击前:
在这里插入图片描述

点击后:

Vue中的computed属性和nextTick方法_第1张图片
此时我们看到msg1和msg3显示的内容还是变换之前的,而msg2显示的内容是变换之后的。其根本原因是因为Vue中DOM更新是异步的
具体原因在Vue的官方文档中详细的解释:
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0)代替。

例如,当你设置vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。

让我们回到之前的例子,执行点击事件之后msg1,msg3中对DOM进行操作,他们拿到的数据还是DOM为更新前的,还是hello,vue,因为上面说了,置vm.someData = ‘new value’,该组件不会立即重新渲染。而msg2是写在nexttick函数里面的,它的执行会延迟到DOM更新之后,也就是msg变成hello,world之后,这样它操作DOM拿到的数据才是更新后的。

这只是一个简单方便理解的例子,要是想深入了解的话,建议还是可以看一下vue.nextTick的源码。

参考

https://www.jianshu.com/p/a7550c0e164f
https://segmentfault.com/a/1190000015070628

你可能感兴趣的:(Vue,vue.js)