首页 > 前端日志 > 前端框架 > Vue中的$nextTick应用 关于Vue的异步更新队列
2018
06-30

Vue中的$nextTick应用 关于Vue的异步更新队列

假设有这么一个需求,在页面中,我们用 v-if 隐藏了某个DIV,在用户进行某个操作后比如点击某个按钮,改变v-if的值,让这个DIV显示出来,同时alert这个div里面的文本内容。

这个需求很简单,我们马上就写出来了:

<div id="app">
    <div id="div" v-if="show">
      cat text 
    </div>
    <button @click='getText'>click here</button>
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script>
  var app = new Vue({
    el:'#app',
    data:{
      show:false,
    },
    methods:{
      getText(){
		this.show = true;
		let text = document.querySelector('#div').innerHTML;
		alert(text)
      },
    },
  });
</script>

 

但是,当我们运行起这段代码,却发现根本不能满足我们的需求,而是报了一个 “TypeError: Cannot read property ‘innerHTML’ of null”的错误。

这是为什么呢?

这里就涉及 Vue 一个重要的概念:异步更新队列。

Vue 在观察到数据变化时并不是直接更新 DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和 DOM 操作。然后,在下一个事件循环 tick 中, Vue 刷新队列井执行实际(己去重的)工作。所以如果你用一个 for 循环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制, DOM 就要重绘 100次,这固然是一个很大的开销。

Vue 会根据当前浏览器环境优先使用原生的 Promise.then 和 MutationObserver,如果都不支持,就会采用 setTimeout 代替。

知道了 Vue 异步更新 DOM 的原理,上面示例的报错也就不难理解了。事实上,在执行this.show = true;同时,div 仍然还是没有被创建出来,直到下一个 Vue 事件循环时,才开始创建。$nextTick 就是用来知道什么时候 DOM 更新完成的,所以上面的示例代码需要修改为:

<div id="app">
    <div id="div" v-if="show">
      cat text 
    </div>
    <button @click='getText'>click here</button>
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script>
  var app = new Vue({
    el:'#app',
    data:{
      show:false,
    },
    methods:{
      getText(){
		this.show = true;
		this.$nextTick(()=>{
			let text = document.querySelector('#div').innerHTML;
			alert(text)
		})
      },
    },
  });
</script>

 

经过这么修改后,再点击按钮,就会弹出“cat text ”了。

理论上,我们应该不用去主动操作 DOM,因为 Vue 的核心思想就是数据驱动 DOM,但在很多业务里,我们避免不了会使用一些第三方库,比如 popper、swiper等 ,这些基于原生 JavaScript 的库都有创建和更新及销毁的完整生命周期,与 Vue 配合使用时,就要利用好$nextTick。

 

最后编辑:
作者:eatdao
这个作者貌似有点懒,什么都没有留下。

留下一个回复

你的email不会被公开。