首页 > 解决方案 > 父/子组件对共享对象的更改没有反应

问题描述

我在 jsfiddle 上举了一个例子:https ://jsfiddle.net/j6hs5fmL/56/

对于这个问题,我创建了一个非常简单的 html 文档:

<div id="app">
    <my-form errors="{&quot;title&quot;: [&quot;This field is required&quot;]}">
        <my-input name="title" value=""></my-input>
    </my-form>
</div>

错误被传递到my-form其中,然后将它们放入我创建的 Collection 类中:

Vue.component('my-form', {
  name: 'my-form',
  props: {
    errors: String
  },
  data() {
    let errors = new Collection(JSON.parse(this.errors));

    return {
      myErrors: errors,
      disabled: errors.any()
    }
  },
  template: `<form>
        <slot></slot>

        <input type="submit" :disabled="disabled" value="Submit">
    </form>`
});

然后my-input组件可以访问错误并显示它们:

Vue.component('my-input', {
  name: 'savvy-input',
  props: {
    name: String
  },
  data() {
    return {
      value: '',
      errors: this.$parent.myErrors
    }
  },
  methods: {
    blur() {
      if (this.value !== "") {
        this.errors.clear(this.name);
      }

      if (this.value === "") {
        this.errors.set(this.name, ["This input is still required"]);
      }

      this.$forceUpdate();
    }
  },
  template: `<div>
        <div v-if="errors.has(this.name)">
            <p>There are errors</p>
            <p v-for="error in errors.get(name)">{{ error }}</p>
        </div>

        <input type="text" :name="name" v-model="value" @blur="this.blur">
    </div>`
});

我现在坚持最后一件事。

输入组件正在对错误集合中的更改做出反应,并删除或重新显示错误消息。

但是表单没有对更改做出反应,并且当错误集合为空时,提交按钮没有启用。

如何让父级对共享错误集合的更改做出反应?或者有没有更好的方法在父表单和子输入之间共享状态?

标签: vue.jsvue-component

解决方案


您的主要问题是您的 Collection 类不是反应性的。它不是一个普通的对象,所以 Vue 并没有在它的元素上使用访问器来发挥它的魔力。您需要在父对象中创建重新分配myErrors自身的方法,以便 Vue 注意到更改:

  methods: {
    refresh() {
      const temp = this.myErrors;

      this.myErrors = null;
      this.myErrors = temp;
    },
    set(field, value) {
      this.myErrors.set(field, value);
      this.refresh();
    },
    clear(field) {
      this.myErrors.clear(field);
      this.refresh();
    }
  },

my-input不应该errors作为一个dataitem,因为它不是一个独立的数据对象;它应该是一个计算:

errors() {
  return this.$parent.myErrors;
}

而不是使用blur事件,您可能应该watch更新value并调用父方法:

  watch: {
    value(newValue) {
        if (newValue !== '') {
        this.$parent.clear(this.name);
      } else {
        this.$parent.set(this.name, ['This input is still required']);
      }
    }
  },

把它们放在一起,小提琴就奏效了。这是插槽对象和父对象的一个​​相当紧密的耦合,但在您的设计中,插槽必须了解父对象的某些内容是固有的。您可能可以使用作用域插槽做一些事情来使事情更整洁。


推荐阅读