VueJs 与父组件的反应性 属性 对象

VueJs reactivity with parent component property object

我很难获得父组件的 属性 对象,它具有动态填充的属性以使值在同一组件内可用。

有点难解释,请看下面的例子:

父组件

<script>
    export default {
        data() {
            return {
                fields: {},
            }
        }
    }
</script>

子组件

<template>
  <select
      @change="update()"
      v-model="field"
  >
      <option
          v-for="option in options"
          :value="option.value"
      >
          {{ option.name }}
      </option>
  </select>
</template>
<script>
    export default {
        props: {
            initialOptions: {
                type: Array,
                required: true
            }
        },
        data() {
            return {
                    field: '',
                options: this.initialOptions
            }
        },
        mounted() {
            if (
                (this.field === undefined || this.field === '') &&
                this.options.length > 0
            ) {
                this.field = this.options[0].value;
            }
            this.update();
        },
        methods: {
            update() {
                this.$emit('input', this.field);
            }
        }
    }
</script>

DOM

<parent-component inline-template>

    <div>

        <child-component>           
            :initial-options="[{..}, {..}]"
          v-model="fields.type_id"
        ></child-component>

    </div>

    <div :class="{ dn : fields.type_id == 2 }">

        // ...

    </div>

</parent-component>

使用 Vue 控制台我可以看到 fields 对象获取所有子组件模型及其关联值,因为它们在安装时发出 input,但是由于某些奇怪的原因 :class="{ dn : fields.type_id == 2 }" does not append the class dn when the selection changes to 2. Dom 似乎没有反映在父组件和子组件之间同步的更改。

关于如何让它工作的任何帮助?

这是我在评论中试图表达的意思。 Vuecannot detect changes to properties that are added dynamically to an object unless you add them using $set。您的 fields 对象没有 type_id 属性,但它会被添加,因为您正在使用 v-model="fields.type_id"。因此,Vue 不知道它何时更改。

在这里,我添加了它,并且文本的颜色如您所料的那样改变了。

console.clear()

Vue.component("child-component", {
  template: `
    <select
        @change="update()"
        v-model="field"
    >
        <option
            v-for="option in options"
            :value="option.value"
        >
            {{ option.name }}
        </option>
    </select>
  `,
  props: {
    initialOptions: {
      type: Array,
      required: true
    }
  },
  data() {
    return {
      field: '',
      options: this.initialOptions
    }
  },
  mounted() {
    if (
      (this.field === undefined || this.field === '') &&
      this.options.length > 0
    ) {
      this.field = this.options[0].value;
    }
    this.update();
  },
  methods: {
    update() {
      this.$emit('input', this.field);
    }
  }
})

new Vue({
  el: "#app",
  data: {
    fields: {
      type_id: null
    }
  }
})
.dn {
  color: red;
}
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <div>
    <child-component :initial-options="[{name: 'test', value: 1}, {name: 'test2', value: 2}]" v-model="fields.type_id"></child-component>
  </div>
  <div :class="{ dn : fields.type_id == 2 }">
    Stuff
  </div>
</div>

看起来您正在尝试制作可重复使用的组件。

我会问自己,当父组件必须处理一半以上的工作时,可重用组件的价值是什么。该组件的名称可能更好...

 <DifficultToUseSelect/>.

本质上,您正在创建一个组件,它本身提供以下所有功能 HTML...

<select></select>

其他一切都由父组件管理。

执行以下任一操作可能会更有用...

  • 将经常需要的选项封装在特定的 select 组件中,如

    StateAbbrevsSelect v-model="状态"

  • 将数据模型的名称传递给 select 组件。然后组件将通过模型加载和管理自己的数据。

  • 将 Web 服务的 URL 传递给组件,然后组件调用它来加载其选项。

同样,我想在这里传达的主要观点是,制作一个可重用的组件,其中超过一半的工作量由父组件处理,实际上不是很可重用。