【问题标题】:Vue.js: Detect change in nested dataVue.js:检测嵌套数据的变化
【发布时间】:2017-03-01 19:22:41
【问题描述】:

这是我的代码的简化版本:

Vue.component('entry', {
  template: '\
    <div>\
        <label>Name: <input type="text" v-model="entry.name"></label>\
    </div>\
  ',
  props: ['entry']
});

Vue.component('entries', {
  template: '\
    <div>\
      <entry v-for="entry in entries" :entry="entry"></entry>\
      <pre>{{ combined }}</pre>\
    </div>\
  ',
  props: ['entries'],
  computed: {
    combined: function() {
      combined = [];
      this.entries.forEach(function(entry) {
        combined.push(entry.name);
      });
      return combined.join("\n");
    }
  }
});

var entries = [
  {name: "Entry 1"},
  {name: "Entry 2"},
  {name: "Entry 3"}
];

这里的JSFiddle:https://jsfiddle.net/msw3Lx98/3/

顶级组件 (entries) 获取对象列表,并为每个对象创建一个子组件 (entry)。子组件将条目数据绑定到输入。

当用户通过键入其中一个输入来修改数据时,顶级组件需要将 combined 的更新值推送到单独的代码位。

我对观察者模型的理解是,如果顶级组件观察entries,它可以检测到何时将事物添加到列表中或从列表中删除,但不能检测到条目中的数据何时发生变化.

然而,顶层组件显然确实以某种方式看到了这种变化,因为当用户输入输入时,combined 的值会更新。

是否有“正确”的方法来检测这种变化?

以下是我探索过的几个选项:

  • 在子组件上定义updated 方法。在该方法中发出一个自定义事件,并在父级中处理此事件。这相当尴尬,我认为它不会很好地扩展。
  • 在父组件上定义一个beforeUpdate 方法——只要子组件发生变化,这个(但不是updated)就会运行。我不知道为什么,而且我觉得味道不对。
  • 在顶级组件中,观察combined 属性。我有点惊讶这行得通,但确实如此。这似乎是最直接的选择,但从 Vue 文档中并没有明显看出计算属性是为了可观察的,所以我不愿意依赖它。

【问题讨论】:

    标签: vue.js vue-component


    【解决方案1】:

    VueJS 的一个承诺是它允许开发人员在考虑业务逻辑的情况下正常编码,而框架使用其 Reactivity system 来处理性能。

    VueJS 通过在实例化组件时在已知对象和数组上定义 getter 和 setter 来做到这一点。

    这是一个更新的小提琴(来自您的版本):https://jsfiddle.net/6wkyfxs6/3/

    如您所见,我在addNewEntry 中添加了一个方法,它允许您将“元素4”添加到列表中。

    前 3 个元素有观察者方法并不奇怪,因为它是在 Vue 实例化时构建的。但是,如果您在我的新小提琴中添加“元素 4”,它最初并不存在,即使它会被观察到并通知更改。这就是反应系统​​的工作原理。

    在更深入的检查中,如果您在 entries 组件 中设置window.entries = this.entries 并检查控制台,您会注意到它在顶层有一个观察者方法 (entries.__ob__)。这是一个屏幕截图(取自 Google Chrome 中的本地版本,而不是在 jsFiddle 上):

    这是 Vue 用来更新和通知自身整个 Array 的变化的,这与使用脏检查的 Angular 1.x 不同。因此,每当您在 Vue 中更改某些内容时,Reactivity System 都会触发并为所有新的和修改的对象设置观察者(以及 getter / setter)。

    如果您直接在 javascript 中添加或更改对象,反应系统将不会触发。特别是在数组的情况下(如您的示例中),有一些警告如下所示:https://vuejs.org/guide/list.html#Caveats,但您的示例避开了这些警告。

    总之,VueJS 允许像我们这样的开发人员在考虑业务逻辑的情况下正常编码,同时它负责性能优化。我认为您不应该使用任何 updatedbeforeUpdate 方法,除非您遇到一些问题 - 在这种情况下,首选应该是提交错误报告而不是解决方法。

    【讨论】:

    • 这只是重申了 Vue 文档中的内容,并没有回答问题。我知道数据发生了变化,Vue 也知道。问题是我可以在哪里正确挂钩我自己的功能以由该更改触发。
    • watch 是在您的示例中挂钩您的对象更改功能的正确位置,例如 entry。但是,如果您尝试观看entries,除非您添加新条目,否则它不起作用。只有计算属性 - combined - 被触发,因为它依赖于单个 entry 对象。
    猜你喜欢
    • 2017-11-16
    • 2018-02-13
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 2019-12-07
    • 1970-01-01
    • 2019-10-01
    • 2017-08-20
    相关资源
    最近更新 更多