Дочерние компоненты VueJS не обновляются при изменении родительских данных

У меня есть компонент parent, который охватывает несколько компонентов child. Я хочу, чтобы родительский компонент управлял состоянием всех своих дочерних элементов. Когда ребенок нажат, я хочу, чтобы родитель знал, и я хочу обновить всех своих братьев и сестер, чтобы они знали, какой из них активен.

ДЕМО JSFIDDLE

Vue.component('child', {
  template: '#childtemplate',
  props: ['index', 'activeIndex'],
  methods: {
    updateActiveIndex: function() {
      console.log("emitting");
      this.$emit('updateEvent', this.index);
    }
  }
});

Vue.component('parent', {
  data: function() {
    return {
      activeIndex: 0
    }
  },
  render: function(createElement) {
    console.log("rendering ai->", this.activeIndex);

    this.$options._renderChildren.forEach(function(item, index) {
      if (item.data === undefined)
      return;

      item.componentOptions.propsData = {
        index: index,
        activeIndex: this.activeIndex
      }
    }.bind(this));

    return createElement('div', {}, this.$options._renderChildren);
  },
  methods: {
    handleToggle: function(index) {
      this.activeIndex = index;
    }
  },
  created: function() {
    this.$on('updateEvent', this.handleToggle);
    //try manually update it, but the children don't update.
    setTimeout(function(){this.activeIndex = 6}.bind(this), 3000);
  }
});

new Vue({
  el: '#app'
})

Я попытался добавить параметр прослушивателя событий в функцию createElement в parent render() следующим образом:

return createElement('div', {on:{updateEvent: this.handleToggle}}, this.$options._renderChildren);

Я попытался установить прослушиватель $on в созданной функции parent. Но это не запускается.

Я попытался вручную обновить activeIndex с тайм-аутом, который обновляет его в корне, но дочерние элементы не обновляются.

Хакское решение, и единственное, что я нашел работающим, это ссылка на обратный вызов $parent непосредственно из дочернего элемента, передающего индекс, затем в родительском цикле через дочерние элементы и назначение свойства вручную. Это вызывает ошибки предупреждения vue, но выполняет свою работу.

Есть ли лучший способ?


person Kiee    schedule 13.03.2017    source источник
comment
В этой ветке есть то, что вы ищете (через реквизиты, магазин или Vuex). Выбранный ответ использовал реквизиты: stackoverflow.com/a/41923080/1695318   -  person iamjpg    schedule 13.03.2017
comment
Вы знаете, какие будут дети? Знаете ли вы, что они являются дочерними компонентами?   -  person Bert    schedule 13.03.2017
comment
Да @BertEvans, они будут child компонентами.   -  person Kiee    schedule 13.03.2017
comment
propsData на самом деле не является реактивным. Это в основном используется для модульного тестирования. Вместо этого используйте props. Это будет работать в интерактивном режиме. Если вы все еще хотите отслеживать состояние каждого дочернего элемента самостоятельно, используйте общедоступный pubsub подход.   -  person Codebryo    schedule 14.03.2017
comment
Я пробовал props перед propsData, и в child компонентах никакие реквизиты не подхватывались. См.: stackoverflow.com/questions/42764535/   -  person Kiee    schedule 14.03.2017


Ответы (1)


Я не уверен, что это лучше, но это работает в этой модифицированной скрипте. По сути, он перебирает слот по умолчанию, отбрасывает все, что не является child, устанавливает соответствующие свойства и включает все, что в данный момент находится в каждом дочернем слоте.

render: function(createElement) {
  console.log("rendering ai->", this.activeIndex);

  const children = [];
  for (let i=0; i < this.$slots.default.length; i++){
    if (!(this.$slots.default[i].tag == "child"))
      continue;

    children.push(createElement(Child, {
      props:{
        index: i,
        activeIndex: this.activeIndex
      },
      on:{
        updateEvent: this.handleToggle
      }
    }, this.$slots.default[i].children))

  }

  return createElement('div', {}, children);
}
person Bert    schedule 13.03.2017
comment
Вы должны использовать Vue так, как он предназначен для работы, и не пытаться снова обрабатывать данные вручную. У Vue есть реактивность, просто используйте ее правильно. - person Codebryo; 14.03.2017
comment
Спасибо, что нашли время ответить, это очень ценно. - person Kiee; 14.03.2017
comment
@Kiee Взгляните на это, используя слоты с областью видимости. codepen.io/Kradek/pen/KWvqRL/?editors=1010 - person Bert; 14.03.2017
comment
Я изменил свой комментарий, так как решил проблему с отдельной областью видимости, и это технически не имеет отношения к первоначальному вопросу. Спасибо еще раз. - person Kiee; 14.03.2017