Reactivity in Depth上的Vue.js文档提及
数据对象中必须存在属性以便Vue 转换它并使其反应
(...)
您必须通过声明所有根级别来初始化Vue实例 前期的反应数据属性,即使只是一个空值
考虑这两个代码片段,其中tags
被定义为空对象并在脚本过程中以两种不同的方式更新:
var vm = new Vue({
el: "#root",
data: {
tags: {}
}
});
vm.tags = {
hello: true,
world: true
};

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<div id="root">
{{tags}}
</div>
&#13;
var vm = new Vue({
el: "#root",
data: {
tags: {}
}
});
vm.tags["hello"] = true
vm.tags["world"] = true
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<div id="root">
{{tags}}
</div>
&#13;
在第一种情况下,内容被正确更新,而在第二种情况下 - 不是。
为什么会这样,尽管在两种情况下都在VM实例化中声明了tags
?
答案 0 :(得分:4)
并不是声明tags
对象,而是在实例化Vue时tags
对象上的属性不存在。
在第二种情况下,您使用索引器向tags
对象添加两个新属性。 Vue 无法检测到添加了这些属性。
这就是$set
方法存在的原因。向对象添加新属性时,需要通过$set
或Vue.set
Vue.set(vm.tags, 'hello', true)
或者,如果你在Vue方法中,
this.$set(this.tags, 'hello', true)
在第一个的情况下,您要添加一个完全不同的对象具有属性。在这种情况下,Vue知道这些属性,并在将新值添加到数据时将它们转换为被动属性。
如果而不是你添加了一个新的空对象而然后添加了属性,那么你将回到与第二个例子相同的情况。
通常,您只想使用空属性初始化对象。
data: {
tags:{
hello: false,
world: false
}
}
在这种情况下,属性将转换为反应属性,并且将检测到更改。
修改强>
@WoJ用笔发布评论,代码如下:
var vm = new Vue({
el: "#root",
data: {
posts: {},
tags: {}
}
});
vm.tags = {
hello: true,
world: true
};
vm.posts["bonjour"] = true
vm.posts["monde"] = true
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="root">
<!-- show all tags which are on -->
{{tags}}
{{posts}}
</div>
&#13;
在此代码中,出现,Vue的posts
属性将使用新的反应属性进行更新,因为它们在呈现Vue时显示在输出中。这里发生的是 属性被添加到posts
对象,这只是javascript的工作原理,你可以添加属性到对象,但 Vue 不知道他们在那里。更具体地说,这些属性不会作为被动属性(getters / setter)添加,这是Vue在添加到Vue的数据发生更改时所知道的。实际上,将这些属性添加到posts
对象不会触发渲染。
那么,为什么新属性会出现在输出中呢?新posts
属性显示在输出中的原因是因为将tags
属性设置为新对象会触发要调度的渲染。 了解Vue呈现不同步,它们是异步的非常重要(请参阅here)。
... Vue执行DOM更新 异步。每当观察到数据变化时,它将打开一个 排队和缓冲在同一事件中发生的所有数据更改 循环。
例如,当您设置vm.someData =&#39;新值&#39;时,该组件 不会立即重新渲染。它将在下一个“tick”中更新, 刷新队列时。
在上面的代码示例中,对tags
的更新会触发要调度的渲染。然后,使用不转换为反应属性的两个新属性更新posts
对象,因为Vue不知道它们存在。 然后一段时间后,计划的渲染发生,Vue使用数据中对象的当前状态更新HTML。由于posts
具有这两个新属性,因此这些属性会呈现给屏幕。但是,对这些属性的更新永远不会触发更新以进行渲染。
要查看这种情况,只需注释掉tags
属性的更新即可。
var vm = new Vue({
el: "#root",
data: {
posts: {},
tags: {}
}
});
//vm.tags = {
// hello: true,
// world: true
//};
vm.posts["bonjour"] = true
vm.posts["monde"] = true
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="root">
<!-- show all tags which are on -->
{{tags}}
{{posts}}
</div>
&#13;
注意,在这种情况下,渲染的Vue 从不更改。
答案 1 :(得分:2)
这是因为在第一种情况下,您在tags
上运行 setter (因为您正在重新分配它) - Vue已经包装并可以检测到。在第二种情况下,您在data: { tags: {
定义中的不的嵌套属性上运行setter,因此它们不会被动反应。
文档中的Change Detection Caveats部分涵盖了这一点,但完全与您的情况相同(嵌套属性情况)。您必须声明您的数据:
data: {
tags: {
hello: null,
world: null,
}
}