不是声明了tags对象,而是实例化Vue时tags对象上的属性不存在。
在第二种情况下,您使用索引器向tags 对象添加两个新属性。 Vue 无法检测到这些属性已被添加。
这就是$set 方法存在的原因。向对象添加新属性时,需要通过$set 或Vue.set 进行添加
Vue.set(vm.tags, 'hello', true)
或者,如果你在一个 Vue 方法中,
this.$set(this.tags, 'hello', true)
在 first 的情况下,您正在添加一个完全不同的对象,该对象 具有 属性。在这种情况下,Vue 知道属性,并在将新值添加到数据时将它们转换为 reactive 属性。
如果改为您添加了一个新的空对象并然后添加了属性,您将回到与第二个示例相同的情况。
通常,您只想用空属性初始化对象。
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
<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>
在这段代码中,显示 Vue 的 posts 属性使用新的响应属性进行了更新,因为它们在 Vue 渲染时显示在输出中。这里发生的是属性被添加到posts对象,这就是javascript的工作原理,你可以给对象添加属性,但是Vue没有知道他们在那里。更具体地说,这些属性不会作为 reactive 属性(getter/setter)添加,这是 Vue 知道何时更改已添加到 Vue 的数据的方式。事实上,将这些属性添加到posts 对象不会触发渲染。
那么,为什么新属性会出现在输出中?新的posts 属性出现在输出中的原因是因为将tags 属性设置为新对象会触发要调度的渲染。 重要的是要知道 Vue 渲染不是同步的,它们是异步的(请参阅 here)。
... Vue 执行 DOM 更新
异步。每当观察到数据变化时,它将打开一个
排队并缓冲同一事件中发生的所有数据更改
循环。
例如,当您设置 vm.someData = 'new value' 时,组件
不会立即重新渲染。它将在下一个“滴答”中更新,
当队列被刷新时。
在上面的代码示例中,对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
<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>
注意,在这种情况下,渲染的 Vue从不改变。