Vue 的小坑
this.$nextTick(callback)
this.$nextTick(callback)的作用
this.$nextTick(callback) 的作用是 在DOM渲染之后立马执行回调函数
在了解了 关键渲染路径之后,我看到 this.$nextTick() 的实现方式,出现了一下疑惑。
this.$nextTick(callback)的原理
它会将回调在异步里面实现。有三种可能。
首先, 如果浏览器支持原生Promise就用Promise,否则就用 mutationObserver,最后才会选择 setTimeout 。
this.$nextTick(callback)与关键渲染路径的冲突
前两个都是微任务,后一个是宏任务。就渲染时机而言,浏览器会在当前微任务执行完之后,启动渲染线程,实现DOM渲染,之后再执行下一个宏任务。这样就会有一个冲突。
原因
因为对于Vue 来说,数据(虚拟DOM)的变化会出发 watcher 。这样就会使得渲染时机变了。所以,使用nextTick 可以在渲染后 执行回调,即便他是一个微任务。你可以尝试着将this.$nextTick(callback)换成Promise 其实效果是一样的。
问题延伸
如果,你尝试将一个不再watcher 监听下的事件改变,例如背景色。这个时候this.$nextTick(callback)就会失效,同样的,Promise和mutationObserver 也会失效。 但是setTimeout本身就是宏任务,所以,你还是可以根据关键渲染路径获取到预期的效果。
附上测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div id="test" style="background-color: red; width: 100px;height: 100px;"></div>
<button @click="changeColor">
Change the Color
</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
msg: 'Hello Vue.',
msg1: '',
msg2: '',
msg3: ''
},
methods: {
changeColor() {
document.getElementById('test').style.backgroundColor = "yellow"
/* this.$nextTick(() => {
document.getElementById('test').style.backgroundColor = "black"
}) */
/* new Promise(resolve => {
resolve();
}).then(() => {
document.getElementById('test').style.backgroundColor = "black"
}) */
setTimeout(() => {
document.getElementById('test').style.backgroundColor = "black"
},0)
}
}
})
</script>
</body>
</html>