【问题标题】:VueJS child components are not updated when parent data changes父数据变化时VueJS子组件不更新
【发布时间】:2017-08-03 19:40:30
【问题描述】:

我有一个 parent 组件,它包装了多个 child 组件。我希望父组件管理其所有子组件的状态。当孩子被点击时,我希望父母知道并且我想更新它的所有兄弟姐妹,以便他们知道哪个是活动的。

JSFIDDLE DEMO

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'
})

我尝试在 parent render() 中的 createElement 函数中添加事件侦听器选项,如下所示:

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

我尝试在parent 创建的函数中设置$on 侦听器。但这并没有触发。

我已尝试手动更新 activeIndex 并在根上更新它,但子节点没有更新。

黑客解决方案,我发现唯一可行的方法是直接从传递索引的子级引用 $parent 回调,然后在父级循环遍历子级并分配手动道具。这会导致 vue 警告错误,但可以完成工作。

有没有更好的方法?

【问题讨论】:

  • 这个线程有你正在寻找的东西(通过道具、商店或 Vuex)。选择的答案是使用道具:stackoverflow.com/a/41923080/1695318
  • 你知道孩子们会是什么吗?你知道它们是“子”组件吗?
  • 是的 @BertEvans ,它们将是 child 组件。
  • propsData 不是反应式的 afaik。这主要用于单元测试。请改用props。这将交互工作。如果您仍想单独跟踪每个孩子的状态,请使用公共pubsub 方法。
  • 我确实在propsData 之前尝试过props,并且在child 组件中没有拾取任何道具。见:stackoverflow.com/questions/42764535/…

标签: javascript data-binding vue.js render vuejs2


【解决方案1】:

我不确定这是否更好,但它适用于 modified fiddle。基本上,它会遍历默认插槽,丢弃任何不是 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);
}

【讨论】:

  • 您应该按照 Vue 的预期工作方式使用 Vue,并且不要再次尝试手动运行数据。 Vue 具有响应性,只需正确利用它即可。
  • 感谢您抽出宝贵时间回答,非常感谢。
  • @Kiee 看看这个,使用作用域插槽。 codepen.io/Kradek/pen/KWvqRL/?editors=1010
  • 我修改了我的评论,因为我解决了单独的 scopedSlot 问题,它在技术上与最初的问题无关。再次感谢。
猜你喜欢
  • 2017-12-31
  • 2017-04-16
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
相关资源
最近更新 更多