在说$nextTick的用法之前,我们先来看一下JS的执行机制是什么?
我们都知道JS是单线程语言,即指某一时间内只能干一件事,有的同学可能会问,为什么 JS
不能是多线程呢?多线程就能同一时间内干多件事情了
是否多线程这个取决于语言的用途,一个很简单的例子,如果同一时间,一个添加了DOM,一个删除了DOM,这个时候语言就不知道是该添还是该删了,所以从应用JS只能是单线程
单线程就意味着我们所有的任务都需要排队,后面的任务必须等待前面的任务完成才能执行,如果前面的任务耗时很长,一些从用户角度上不需要等待的任务就会一直等待,这个从体验角度上来讲是不可接受的,所以JS
中就出现了异步的概念。
了解了JS的执行机制后,我们开始学习vue中的$nextTick
定义: 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
案例
<template>
<div>
<button @click="testClick()" ref="a">{{msg}}</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg:"原始值",
}
},
methods:{
testClick(){
this.msg="修改值";
console.log(this.$refs.a.innerText); //this.$refs.a获取指定DOM,输出:原始值
}
}
}
</script>
以上的案例输出的是 “原始值”,并未按照顺序输出 “修改值”,当我们使用this.$nextTick方法后
methods:{
testClick(){
this.msg="修改值";
this.$nextTick(() => {
console.log(this.$refs.a.innerText); //输出:修改值
});
}
}
注意:Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM
什么时候需要this.nextTick()?
需要等待渲染完成后执行的一些方法
初始化绑定或操作 DOM
比如在 created 和 mounted 回调中,需要操作渲染好的 DOM,则需要在 nextTick 中执行相关逻辑,这在必须使用一些老的需要绑定 DOM 的库时很有用。
比如,在加载 UEditor 时,可能会这样玩
<template>
<script id="container" name="content" type="text/plain"> 这里写你的初始化内容 </script>
</template>
<script>
export default {
mounted() {
this.nextTick(() => {
var ue = UE.getEditor('container');
});
}
}
</script>
获取元素宽度
在 Vue 中获取元素宽度有两种方式,第一种是通过 $refs[ref名称].style.width
,第二种可以使用传统操作 DOM 的方式获取,但这两者要获取到准确的元素宽度,则需要在 DOM 渲染完毕后执行。
<template>
<p ref="myWidth" v-if="showMe">{{ message }}</p>
<button @click="getMyWidth">获取p元素宽度</button>
</template>
<script>
export default {
data() {
return {
message: "Hello world!",
showMe: false,
},
}
methods: {
getMyWidth() {
this.showMe = true;
//this.message = this.refs.myWidth.offsetWidth;
//报错 TypeError: this.refs.myWidth is undefined
this.nextTick(()=>{
//dom元素更新后执行,此时能拿到p元素的属性
this.message = this.refs.myWidth.offsetWidth;
})
}
}
}
</script>