vue JS не распространяет изменения от родителя к компоненту

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

Все работает нормально, как и ожидалось, если узел содержит атрибут «имя» (в приведенном ниже фрагменте с комментариями) при инициализации. Но если атрибут имени добавляется на более позднем этапе выполнения (здесь для демонстрации я добавил установленный тайм-аут и применил его). Компонент выдает ошибку и изменения не отражаются. Я не уверен, как я могу распространять изменения динамических атрибутов в компоненте, которые генерируются на основе других событий вне компонента.

В основном я хотел обновить компонент, который динамически отображает различные типы виджетов на основе ответа сервера на основе переданного ему свойства. Всякий раз, когда свойство обновляется, я хотел бы, чтобы сам компонент обновлялся. Почему двусторонняя привязка не работает должным образом в Vuejs?

Vue.component('greeting', {
    template: '#treeContainer',
    props: {'message':Object},
    watch:{
        'message': {
            handler: function(val) {
                console.log('###### changed');
            },
            deep: true
        }
    }
});

var data = {
    note: 'My Tree',
    // name:"Hello World",
    children: [
      { name: 'hello' },
      { name: 'wat' }
    ]
}

function delayedUpdate() {
    data.name='Changed World';
    console.log(JSON.stringify(data));
}

var vm = new Vue({
    el: '#app',
    data:{
        msg:data
    },
    method:{ }
});

setTimeout(function(){ delayedUpdate() ;}, 1000)
<script src="https://vuejs.org/js/vue.js"></script>
<div id="app">
  <greeting :message="msg"></greeting>
</div>
<script  type="text/x-template"  id="treeContainer">
	<h1>{{message.name}}</h1>
</script>

Изменить 1: ответ @Craig помогает мне распространять изменения на основе имени атрибута и путем вызова набора для каждого атрибута. Но что, если данные были сложными и приветствие основывалось на множестве атрибутов узла. Здесь, в примере, я рассмотрел простой вариант использования, но в реальном мире виджет основан на множестве атрибутов, динамически отправляемых с сервера, и каждый атрибут виджета различается в зависимости от типа виджета. Например, «Добро пожаловать, {{message.name}}. Температура в {{message.location}} составляет {{ message.temp}}». И так далее. Поскольку атрибуты узла различаются, можем ли мы каким-либо образом обновить полное дерево без обхода всего дерева в нашем коде javascript и набора вызовов для каждого атрибута. Есть ли что-нибудь в структуре VUE, которая может позаботиться об этом?


person Dev Loper    schedule 23.01.2017    source источник


Ответы (1)


Vue не может обнаружить добавление или удаление свойства, если вы не используете метод set (см.: https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats), поэтому вам нужно сделать:

Vue.set(data, 'name', 'changed world')

Вот JSFiddle: https://jsfiddle.net/f7ae2364/

ИЗМЕНИТЬ

В вашем случае, я думаю, вам придется отказаться от просмотра prop и вместо этого пойти на шина событий, если вы хотите избежать обхода ваших данных. Итак, сначала вы настраиваете глобальную шину для прослушивания вашего компонента:

var bus = new Vue({});

Затем, когда вы получаете новые данные, вы $emit передаете событие на шину с обновленными данными:

bus.$emit('data-updated', data);

И прослушайте это событие внутри вашего компонента (которое можно поместить внутри созданного хука), обновите сообщение и заставьте vue повторно отобразить компонент (здесь я использую ES6):

created(){
   bus.$on('data-updated', (message) => {
     this.message = message;
     this.$forceUpdate();
   })
}

Вот JSFiddle: https://jsfiddle.net/9trhcjp4/

person craig_h    schedule 23.01.2017
comment
Спасибо за обновление, а что, если данные были сложными и приветствие основывалось на многих атрибутах узла. Здесь, в примере, я рассмотрел простой вариант использования, но в реальном мире виджет основан на множестве атрибутов, динамически отправляемых с сервера, и каждый атрибут виджета различается в зависимости от типа виджета. например Добро пожаловать, {{message.name}} . Температура в {{ message.location }} составляет {{ message.temp}} . и так далее. Поскольку атрибуты узла различаются, можем ли мы каким-либо образом обновить полное дерево без обхода всего дерева и набора вызовов для каждого атрибута? - person Dev Loper; 24.01.2017
comment
Также ваш код не работает, если я добавлю data.name='Changed world' перед Vue.set(data,'name', 'changed world1') . Это означает, что если объект уже обновился вне области действия, то даже установленная операция не поможет при установке его на тот же ключ. Любые советы о том, как преодолеть это ограничение? - person Dev Loper; 24.01.2017
comment
Спасибо @Крейг. Решения работают без глюков. - person Dev Loper; 24.01.2017