Content Table

Vue DOM 更新完成后再执行函数

Vue 的数据变化后会更新 DOM,但只能保证在当前 tick 里面的代码全部执行完毕后更新 (事件队列),不能保证数据一变化后就能用 document.querySelector() 立即获取到最新的 DOM。要保证在 DOM 更新以后执行某一块代码,就必须把这块代码放到下一次事件循环里面,比如 setTimeout(fn, 0),这样 DOM 更新后,就会立即执行这块代码。

有些时候 DOM 更新完成后执行某些操作是有必要的,这时就可以使用 Vue.nextTick() 注册一个函数放到 Vue 的事件队列里,使其在下一个 tick 被执行。

例如使用 Vue + Semantic Ui 创建 Popup,新创建的 Popup 需要执行 popup() 后才会生效,此时在 DOM 更新完成后需要执行一下 popup() 函数。

一般有 3 种方式调用 Vue.nextTick():

  • 普通事件处理函数中,下面的 [[1]],当有多个地方修改同一个变量时,每个地方都需要执行一次
  • 监听指定的数据变化时,下面的 [[2]],粒度细,只与数据是否变化有关,和修改数据的地方无关
  • updated() 回调中,下面的 [[3]],只要 DOM 变化了都会调用,无关的数据变化时都会调用,最省事,但是需要小心测试看看是否有副作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="http://cdn.staticfile.org/semantic-ui/2.2.7/semantic.min.css">
<script src="http://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdn.staticfile.org/semantic-ui/2.2.7/semantic.min.js"></script>
<script src="http://cdn.staticfile.org/vue/2.0.3/vue.js"></script>
<script src="http://cdn.staticfile.org/layer/2.3/layer.js"></script>

<style media="screen">
body {
padding: 20px;
}
</style>
</head>

<body>
<div id="vue-tags">
<div class="ui button" @click="addTag()">Add Tag</div><br><br>

<a class="ui tag label" :data-content="tag" v-for="tag in tags" v-html="tag"></a>
</div>

<script>
var count = 3;
new Vue({
el: '#vue-tags',
data: {
tags: [1, 2]
},
methods: {
addTag: function() {
this.tags.push(count++);

// [[1]] 事件处理函数中调用
// this.$nextTick() 也可以
// Vue.nextTick(function() {
// $('.tag').popup({ position: 'bottom left' });
// });
}
},
watch: {
// [[2]] 指定变量数据变化时调用
tags: function() {
Vue.nextTick(function() {
$('.tag').popup({ position: 'bottom left' });
});
}
},
// [[3]] 只要 DOM 更新了就会调用
updated: function() {
// Vue.nextTick(function() {
// $('.tag').popup({ position: 'bottom left' });
// });
}
});

$('.tag').popup({ position: 'bottom left' });
</script>
</body>

</html>

参考: Vue nextTick 源码解读