确实,只有在没有其他解决方案的情况下才应该使用观察者,因为它可能会导致副作用并使调试变得一团糟。在您的情况下,可能没有必要。
计算属性从不用于直接更新值。所以这也不是一个选择。您应该尽可能使用它们,但仅用于将值转换为不同的格式,作为方法或其他计算属性或模板中的辅助值。
一般来说,您应该考虑您的组件架构。这里的问题是您使用对象作为 v-model 值,这也可能导致副作用。当然你可以这样做,但是维护起来更复杂,你必须正确地实现它。假设您有多个组件将此对象用作v-model 值。在最坏的情况下,组件会覆盖它们不应该覆盖的值。为了防止这种情况,您通常只使用单个原始值作为v-model,而不是对象。
实际上,您实现它的方式是偶然的。在 Vue 2 中,v-model 要求您从子组件向父组件发出 input 事件,因此值会在父组件中更新(查看此处了解更多详细信息:https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components)。在您的情况下,它可以工作,因为您的 v-model 是一个对象 - 意味着对该对象的引用被传递给子组件,并且您正在更新此对象引用的属性。
所以,让我们稍微重构一下您的代码(未经测试,但概念应该很清楚):
1.假设您在子组件中只有少数值要更新
在您的情况下,v-model 不是一个选项,因为您有 2 个模型值要在同一个组件中更新。 Vue 3 会支持它 (https://v3.vuejs.org/guide/component-custom-events.html#multiple-v-model-bindings),但是当您使用 Vue 2 时,我建议您手动完成:
<template>
<user-component
:nationality="apiData.user.nationality"
:stateless="apiData.user.stateless"
@update:nationality="onUpdateNationality"
@update:stateless="onUpdateStateless"
/>
</template>
<script>
export default {
name: "MyForm",
components: {
UserComponent
},
data() {
return {
apiData: {},
};
},
async mounted() {
const response = await ApiService.getData();
this.apiData = response.data;
},
methods: {
onUpdateNationality (value) {
this.apiData.user.nationality = value
},
onUpdateStateless (value) {
this.apiData.user.stateless = value
if (value) {
this.apiData.user.nationality = null // You also could handle it in your child component
}
}
}
};
</script>
<template>
<b-form-group
label="Nationality"
>
<b-form-input
:value="nationality"
@input="onUpdateNationality($event.target.value)"
/>
<b-form-checkbox
:checked="stateless"
@click="onClickStateless"
>
Stateless
</b-form-checkbox>
</b-form-group>
</template>
<script>
export default {
name: "UserCompoent",
props: {
nationality: {
type: String,
required: true
},
stateless: {
type: Boolean,
required: true
}
},
methods: {
onClickStateless () {
this.$emit('update:stateless', !this.stateless)
},
onUpdateNationality (nationality) {
this.$emit('update:nationality', nationality)
}
}
};
</script>
2。假设您的子组件更新了许多道具
<template>
<user-component
:user="apiData.user"
@update:user="onUpdateUser"
/>
</template>
<script>
export default {
name: "MyForm",
components: {
UserComponent
},
data() {
return {
apiData: {},
};
},
async mounted() {
const response = await ApiService.getData();
this.apiData = response.data;
},
methods: {
onUpdateUser ({ nationality, stateless }) {
this.apiData.user.nationality = nationality
this.apiData.user.stateless = stateless
if (stateless) {
this.apiData.user.nationality = null // You also could handle it in your child component
}
}
}
};
</script>
<template>
<b-form-group
label="Nationality"
>
<b-form-input
:value="form.nationality"
@input="onUpdateNationality($event.target.value)"
/>
<b-form-checkbox
:checked="form.stateless"
@click="onClickStateless"
>
Stateless
</b-form-checkbox>
</b-form-group>
</template>
<script>
export default {
name: "UserCompoent",
props: {
user: {
type: Object,
requird: true
}
},
data () {
return {
form: {
nationality: this.user.nationality,
stateless: this.user.stateless
}
}
}
methods: {
onClickStateless () {
this.form.stateless = !this.form.stateless
this.$emit('update:user', this.form)
},
onUpdateNationality (nationality) {
this.form.nationality = nationality
this.$emit('update:user', this.form)
}
}
};
</script>