【问题标题】:How to declare a nested reactive component?如何声明嵌套的反应组件?
【发布时间】:2019-11-06 07:12:48
【问题描述】:

在阅读文档中的"Reactivity in Depth" 时,我看到两点我不确定如何解释:

当您将纯 JavaScript 对象作为其数据传递给 Vue 实例时 选项,Vue 将遍历其所有属性并转换它们 使用Object.defineProperty获取/设置者

(...)

由于现代 JavaScript 的局限性(以及放弃 Object.observe),Vue 无法检测到属性添加或 删除。由于Vue执行getter/setter转换过程 在实例初始化期间,数据中必须存在属性 对象,以便 Vue 对其进行转换并使其具有反应性。

这与嵌套对象有什么关系,例如

[
  {
    "a": 1,
    "b": [
      {
        "c": 1
      },
      ...
    ]
  },
  {
    "a": 10,
    "b": [
      {
        "c": 10
      },
      ...
    ]
  },
  ...
]

具体来说,应该如何将这样的对象呈现给data(),使其具有反应性?

data() {
    return {
        likeThis: [],
        orLikeThat: [{}],
        orMoreDetailed: [{a: null, b:[]}],
        orTheFullStucture: [{a: null, b:[{c: null}]}]
    }
}

【问题讨论】:

    标签: javascript vue.js reactive-programming


    【解决方案1】:

    我认为你误解了property addition/deletion caveat。您引用的文档第一部分中的语句适用于您的示例对象。如果将该对象设置为 data 方法返回的对象的属性,则该对象中的所有内容都将是反应式的。

    这是一个简单的例子,我在data 方法中将您的对象设置为myNestedData。我已经通过v-modelmyNestedData[0].b[0].c 绑定到一个输入元素,您可以看到对该值的更改反映在myNestedData 对象本身中。

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    
    new Vue({
      el: '#app',
      data() {
        return {
          myNestedData: [{
            "a": 1,
            "b": [{ 
              "c": 1
            }]
          }, {
            "a": 10,
            "b": [{
              "c": 10
            }]
          }]
        };
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <input v-model="myNestedData[0].b[0].c" type="number">
      <br>
      {{ myNestedData }}
    </div>

    你在最后一段代码中给出的任何例子都是完全反应式的,就像我上面的例子一样。属性添加/删除警告仅在您尝试从这些反应性数据对象中添加或删除属性时才起作用。

    这是一个简单的示例,其中foo 属性最初在data 方法中设置为[{ a: 'apple' }]。然后this.foo[0].b在组件的created钩子中设置为'banana'。但是,因为 this.foo[0]b 属性以前不存在,所以该属性不是反应性的。您可以通过将通过v-model 绑定到foo[0].b 的第二个输入的值更改来看到这一点。更改该值不会更新 foo 中该属性的值。

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    
    new Vue({
      el: '#app',
      data() {
        return {
          foo: [{ a: 'apple' }]
        };
      },
      created() {
        this.foo[0].b = 'banana';
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <input v-model="foo[0].a">
      <input v-model="foo[0].b">
      <br>
      {{ foo }}
    </div>

    【讨论】:

    • 感谢您的详细解答。尚不清楚的一点是可以添加和不能添加的内容。在您的示例中,您添加了一个非反应性this.foo[0].b。但是如果foo被初始化为[],这样的加法是否可行? (因为添加到列表中的任何内容显然都是“插入”,而不知道插入的是什么)
    • 可以添加任何东西,但向已声明的对象添加属性不会是反应性的。 See the docs on the change detection caveats. 在我的示例中,如果 foo 被初始化为 [] 我可以将对象 { b: 'banana' } 推送到数组,然后 this.foo[0].b 将是反应性的,因为我没有在该过程中向任何现有对象添加新属性。
    • 啊,好的,我明白了。这特别是添加到 objectproperty,它不会是响应式的。非常感谢您澄清这一点。
    猜你喜欢
    • 2017-01-26
    • 2022-01-22
    • 2019-03-27
    • 2012-12-31
    • 2015-08-07
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2018-09-10
    相关资源
    最近更新 更多