Vue 3 使用 v-model 作为 props 而不是 :prop 和 @emit
Vue 3 using v-model as props instead of :prop and @emit
所以我读了好几遍 this 文章,据我所知,我可以使用 v-model 而不是 props 将值从父组件传递到子组件并自动发出事件当 prop 的值在子项中被修改时,从而以更少的代码获得双向绑定(无需捕获父项中发出的事件)。然而它并没有像我认为的那样工作。
这是我的代码:
<template>
<!-- This is ParentComponent.vue -->
<ChildComponent v-model:documents="user.documents" />
</template>
<script lang="ts">
// This is ParentComponent.vue
import { Vue, Options } from 'vue-class-component';
import UserClass from '@/some/place/UserClass';
import ChildComponent from '@/components/ChildComponent.vue';
@Options({
components: {
ChildComponent,
}
})
export default class ParentComponent extends Vue {
// Local state.
user: UserClass = new UserClass();
}
</script>
<template>
<!-- This is ChildComponent.vue -->
<section v-for="document in documents" :key="document.id">
{{ document.name }}
<button @click="remove(document.id)">Delete document</button>
</section>
</template>
<script lang="ts">
// This is ChildComponent.vue
import { Vue, Options } from 'vue-class-component';
import IDocument from '@/interfaces/IDocument';
@Options({
props: ['documents'],
emits: ['update:documents'],
})
export default class ChildComponent extends Vue {
// Types.
documents!: IDocument[];
// Methods.
remove(documentId: string): void {
this.documents = this.documents.filter((document) => document.id !== documentId);
}
}
</script>
我希望当点击子组件内的按钮时,它应该触发“remove()”方法,而不是直接将新值赋给 this.documents,它应该发出 update:documents 事件,该事件又应该被父组件捕获并应用于更新父组件的本地状态。
但是,我收到以下警告:
正在尝试改变道具“文档”。道具是只读的。
并出现以下错误:
未捕获类型错误:代理集处理程序为 属性 '"documents"'
返回 false
我哪里错了?提前致谢。
我想我错过了 v-model 工作原理的一个重要特性。我假设像这样使用 v-model 传递值
<ChildComponent v-model:documents="user.documents" />
会自动发出 update:documents 事件,当 documents prop 的值在 ChildComponent 中改变时。但似乎您仍然需要手动发出此事件,如下所示:
<script lang="ts">
// This is ChildComponent.vue
import { Vue, Options } from 'vue-class-component';
import IDocument from '@/interfaces/IDocument';
@Options({
props: ['documents'],
emits: ['update:documents'],
})
export default class ChildComponent extends Vue {
// Types.
documents!: IDocument[];
// Methods.
remove(documentId: string): void {
// The user.documents in the ParentComponent would be overriden with filtered array, generated here in the child.
this.$emit('update:documents', this.documents.filter((document) => document.id !== documentId));
}
}
</script>
所以我读了好几遍 this 文章,据我所知,我可以使用 v-model 而不是 props 将值从父组件传递到子组件并自动发出事件当 prop 的值在子项中被修改时,从而以更少的代码获得双向绑定(无需捕获父项中发出的事件)。然而它并没有像我认为的那样工作。
这是我的代码:
<template>
<!-- This is ParentComponent.vue -->
<ChildComponent v-model:documents="user.documents" />
</template>
<script lang="ts">
// This is ParentComponent.vue
import { Vue, Options } from 'vue-class-component';
import UserClass from '@/some/place/UserClass';
import ChildComponent from '@/components/ChildComponent.vue';
@Options({
components: {
ChildComponent,
}
})
export default class ParentComponent extends Vue {
// Local state.
user: UserClass = new UserClass();
}
</script>
<template>
<!-- This is ChildComponent.vue -->
<section v-for="document in documents" :key="document.id">
{{ document.name }}
<button @click="remove(document.id)">Delete document</button>
</section>
</template>
<script lang="ts">
// This is ChildComponent.vue
import { Vue, Options } from 'vue-class-component';
import IDocument from '@/interfaces/IDocument';
@Options({
props: ['documents'],
emits: ['update:documents'],
})
export default class ChildComponent extends Vue {
// Types.
documents!: IDocument[];
// Methods.
remove(documentId: string): void {
this.documents = this.documents.filter((document) => document.id !== documentId);
}
}
</script>
我希望当点击子组件内的按钮时,它应该触发“remove()”方法,而不是直接将新值赋给 this.documents,它应该发出 update:documents 事件,该事件又应该被父组件捕获并应用于更新父组件的本地状态。
但是,我收到以下警告:
正在尝试改变道具“文档”。道具是只读的。
并出现以下错误:
未捕获类型错误:代理集处理程序为 属性 '"documents"'
返回 false我哪里错了?提前致谢。
我想我错过了 v-model 工作原理的一个重要特性。我假设像这样使用 v-model 传递值
<ChildComponent v-model:documents="user.documents" />
会自动发出 update:documents 事件,当 documents prop 的值在 ChildComponent 中改变时。但似乎您仍然需要手动发出此事件,如下所示:
<script lang="ts">
// This is ChildComponent.vue
import { Vue, Options } from 'vue-class-component';
import IDocument from '@/interfaces/IDocument';
@Options({
props: ['documents'],
emits: ['update:documents'],
})
export default class ChildComponent extends Vue {
// Types.
documents!: IDocument[];
// Methods.
remove(documentId: string): void {
// The user.documents in the ParentComponent would be overriden with filtered array, generated here in the child.
this.$emit('update:documents', this.documents.filter((document) => document.id !== documentId));
}
}
</script>