变化检测问题

图片描述

图片描述

Vue 不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive property)。然而它可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上

是否如上图demo代码示例那样,不能动态添加与a属性同级的新属性,只能将新属性添加到嵌套的对象a里?

PS:页面渲染结果为1 2

阅读 16.4k
2 个回答

首先,楼主的结论是正确的,如果尝试在已经创建的实例上动态添加新的根级响应式属性的话,会报如下的错误:

[Vue warn]: Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.

那么,为什么不允许添加新的根级响应式属性?

简单地解读一下,比如我们有以下一个Vue实例,输出到控制台看看结构:

var test = new Vue({
    el: '#app',
    data: {
        a: 'Welcome to your Vue.js app!',
        b: 'http://vuejs.org/guide/'
    }
})

我们可以看到实例下也有a、b属性,而不只是在$data对象里面,为什么?

原因是Vue实例创建时会根据data中的属性进行一系列的初始化操作。举个例子,实例创建时,会在实例上注册对应的ProxyGetter和ProxySetter,在Vue的源码里可以找到这样一段代码:

function proxy (target, sourceKey, key) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  };
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val;
  };
  Object.defineProperty(target, key, sharedPropertyDefinition);
}

这是个什么东西?字面意思,getter代理器和setter代理器呗。a、b属性明明在test.$data对象下,为什么我们能够访问,甚至修改它们?就是ProxyGetter和ProxySetter起的作用。

说到这里,你大概会想到,其实初始化Vue实例时不只做了这么点操作,还有很多很多,都是跟data有关的。那么,如果你添加的是根响应式属性,那么要做的工作几乎和重新初始化一个Vue实例差不多了。。。

data是放所有的数据。你可以在a外面再套一层就可以添加与a同级的属性了

推荐问题
宣传栏