关于Reactivity in Depth 的Vue.js 文档提到
数据对象中必须存在一个属性,以便 Vue 转换它并使其具有反应性
(……)
您必须通过预先声明所有根级响应式数据属性来初始化 Vue 实例,即使只有一个空值
考虑这两个代码片段,其中tags
定义为空对象并在脚本执行过程中以两种不同的方式更新:
var vm = new Vue({
el: "#root",
data: {
tags: {}
}
});
vm.tags = {
hello: true,
world: true
};
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<div id="root">
{{tags}}
</div>
Run Code Online (Sandbox Code Playgroud)
var vm = new Vue({
el: "#root",
data: {
tags: {}
}
});
vm.tags["hello"] = true
vm.tags["world"] = true
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<div id="root">
{{tags}}
</div>
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,内容被正确更新,而在第二种情况下 - 没有。
为什么会这样,尽管在这两种情况下tags
都是在 VM 实例化时声明的?
不是声明了tags
对象,而是tags
实例化Vue时对象上的属性不存在。
在第二种情况下,您将tags
使用索引器向对象添加两个新属性。Vue无法检测到这些属性已添加。
这就是该$set
方法存在的原因。当您向对象添加新属性时,您需要通过$set
或Vue.set
Vue.set(vm.tags, 'hello', true)
Run Code Online (Sandbox Code Playgroud)
或者,如果您在 Vue 方法中,
this.$set(this.tags, 'hello', true)
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,您要添加一个完全不同的具有属性的对象。在这种情况下,Vue 知道这些属性,并在将新值添加到数据时将它们转换为响应式属性。
相反,如果您添加了一个新的空对象,然后添加了属性,您将回到与第二个示例相同的情况。
通常,您只想使用空属性初始化对象。
data: {
tags:{
hello: false,
world: false
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这些属性将转换为反应性属性,并且会检测到更改。
编辑
@WoJ 用钢笔发表了一条评论,代码如下所示:
Vue.set(vm.tags, 'hello', true)
Run Code Online (Sandbox Code Playgroud)
this.$set(this.tags, 'hello', true)
Run Code Online (Sandbox Code Playgroud)
在这段代码中,posts
Vue的属性似乎被更新为新的反应性属性,因为它们在 Vue 呈现时显示在输出中。这到底是怎么发生的是,性能都加入到posts
对象,这是多么的JavaScript的作品,你可以将属性添加对象,但Vue公司并不知道它们的存在。更具体地说,这些属性不是作为反应性属性(getter/setter)添加的,这是 Vue 知道何时添加到 Vue 的数据发生更改的方式。事实上,将这些属性添加到posts
对象不会触发渲染。
那么,为什么新属性会出现在输出中呢?posts
输出中显示新属性的原因是将tags
属性设置为新对象会触发要调度的渲染。重要的是要知道 Vue 渲染不是同步的,它们是异步的(请参阅此处)。
... Vue 异步执行 DOM 更新。每当观察到数据更改时,它将打开一个队列并缓冲在同一事件循环中发生的所有数据更改。
例如,当您设置 vm.someData = 'new value' 时,组件不会立即重新渲染。当队列被刷新时,它将在下一个“滴答”中更新。
在上面的代码示例中,更新tags
触发了要调度的渲染。然后,posts
使用两个新属性更新对象,这些属性不会转换为响应式属性,因为 Vue 不知道它们存在。然后一段时间后,预定的渲染发生,Vue 用数据中对象的当前状态更新 HTML 。由于posts
确实有这两个新属性,因此这些属性会呈现到屏幕上。但是,对这些属性的更新永远不会触发要呈现的更新。
要查看这种情况,只需注释掉对tags
属性的更新即可。
data: {
tags:{
hello: false,
world: false
}
}
Run Code Online (Sandbox Code Playgroud)
var vm = new Vue({
el: "#root",
data: {
posts: {},
tags: {}
}
});
vm.tags = {
hello: true,
world: true
};
vm.posts["bonjour"] = true
vm.posts["monde"] = true
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,渲染的 Vue永远不会改变。
归档时间: |
|
查看次数: |
1306 次 |
最近记录: |