Vue 3 使用 v-model 作为 props 而不是 :prop 和 @emit

Igo*_*rov 6 typescript vue-class-components vuejs3

因此,我已经阅读了这篇文章几次,据我了解,我可以使用 v-model 而不是 props,将值从父组件传递到子组件,并在子组件中修改 prop 的值时自动发出事件,从而用更少的代码获得双向绑定(不需要捕获父级中发出的事件)。然而它并没有按照我认为应该的方式工作。

这是我的代码:

<template>
  <!-- This is ParentComponent.vue -->
  <ChildComponent v-model:documents="user.documents" />
</template>
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我希望当单击子组件内的按钮时,它应该触发“remove()”方法,而不是直接向 this.documents 分配新值,它应该发出 update:documents 事件,该事件又应该由父组件捕获并用于更新父组件的本地状态。

但相反,我收到以下警告:

试图改变道具“文档”。道具是只读的。

并出现以下错误:

未捕获的类型错误:代理集处理程序为属性“文档”返回 false

我哪里错了?提前致谢。

Igo*_*rov 6

我想我错过了 v-model 工作原理的一个重要功能。我假设像这样使用 v-model 传递值

<ChildComponent v-model:documents="user.documents" />
Run Code Online (Sandbox Code Playgroud)

当 ChildComponent 中的 Documents 属性的值发生更改时,会自动发出 update:documents 事件。但似乎您仍然需要手动发出此事件,如下所示:

<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>
Run Code Online (Sandbox Code Playgroud)