Vue.js : Обнаружение изменений во вложенных данных

#vue.js #vue-component

#vue.js #vue-компонент

Вопрос:

Вот упрощенная версия моего кода:

 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 не очевидно, что вычисляемые свойства предназначены для просмотра, поэтому я неохотно полагаюсь на это.

Ответ №1:

Одним из преимуществ VueJS является то, что он позволяет разработчикам нормально кодировать с учетом бизнес-логики, в то время как фреймворк заботится о производительности, используя свою систему реактивности.

VueJS делает это, определяя методы получения и установки для известных объектов и массивов при создании экземпляра компонента.

Вот обновленная скрипка (разветвленная из вашей версии):https://jsfiddle.net/6wkyfxs6/3 /

Как вы можете видеть, я добавил метод в addNewEntry , который позволяет добавить «Элемент 4» в список.

Неудивительно, что первые 3 элемента имеют методы наблюдателя, поскольку они были созданы при создании экземпляра Vue. Но если вы добавите «Элемент 4» в мою новую скрипку, которого изначально не было, даже он будет замечен, и изменения будут уведомлены. Так работает система реактивности.

При более глубокой проверке, если вы установите window.entries = this.entries внутри компонента entries и проверите в консоли, вы заметите, что у него есть метод observer ( entries.__ob__ ) на верхнем уровне. Вот скриншот (взятый из локальной версии в Google Chrome, а не на jsFiddle):

Vue.js наблюдатель для объекта массива

Это то, что Vue использует для обновления и уведомления себя об изменениях в массиве в целом, в отличие от Angular 1.x, который использует грязную проверку. Таким образом, каждый раз, когда вы что-то меняете внутри Vue, система реактивности запускает и настраивает наблюдателей (вместе с получателями / установщиками) для всех новых и измененных объектов.

Система реактивности не сработает, если вы добавите или измените объект непосредственно в javascript. В частности, в случае массивов (как в вашем примере), есть некоторые предостережения, как показано здесь:https://vuejs.org/guide/list.html#Caveats , но в вашем примере отсутствуют эти оговорки.

Таким образом, VueJS позволяет разработчикам вроде нас нормально кодировать с учетом бизнес-логики, одновременно заботясь об оптимизации производительности. Я не думаю, что вам следует использовать какой-либо из методов updated или beforeUpdate , если вы не столкнетесь с некоторыми проблемами — в этом случае первым выбором должно быть сообщение об ошибке вместо обходных путей.

Комментарии:

1. Это просто повторяет то, что есть в документах Vue, что не отвечает на вопрос. Я знаю, что данные изменились, и Vue тоже это знает. Вопрос в том, где я могу правильно подключить свою собственную функциональность, которая будет вызвана этим изменением.

2. watch это правильное место для подключения вашей функциональности к изменениям объекта, как entry в вашем примере. Но если вы попытаетесь посмотреть entries , это не сработает, если вы не добавляете новые записи. Запускается только вычисляемое свойство — combined -, поскольку оно зависит от отдельных entry объектов.