vue3 中使用 props, emits 并指定其类型与默认值

Posted 鱼干拌饭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3 中使用 props, emits 并指定其类型与默认值相关的知识,希望对你有一定的参考价值。

前言

本文主要描述 vue3 中 defineProps 与 defineEmits 分别在 JS 环境和 TS 环境中的使用方法。

defineProps 的使用

defineProps在使用的时候无需引入,默认是全局方法。

  • 在 js 开发的 vue3 项目中使用
const props = defineProps(
  attr1: 
    type: String, // S 必须大写
    default: "",
  ,
  attr2: Boolean,
  attr3: 
    type: Number,
    required: true,
  ,
);

js 环境中使用与 vue2 的使用方法类似,只是选项式 API 换成了组合式 API。定义 props 类型与默认值都与 vue2 类型,vue3 中使用的是definePropsAPI,在此不多介绍。

  • 在 ts 开发的 vue3 项目中使用
interface DeatilInf 
  aaa: string;
  bbb: number;


const props = withDefaults(
  // 参数一:定义props类型:? 代表非必传字段, :号后面紧跟的是数据类型或自定义接口, | 或多种类型
  defineProps<
    name: string;
    age?: number;
    detail?: DeatilInf | any;
  >(),
  // 参数二:指定非必传字段的默认值
  
    age: 18,
    detail: ,
  
);

使用 typeScript 开发 vue3 项目定义 props 主要使用的 API 有两个: defineProps 定义接收的 props 、withDefaults 定义接收的类型。

当然,你也可以使用上述 js 环境使用的方法定义 props,但这样做就失去了使用 TS 的意义了。

defineEmits 的使用

与 vue2 不同:vue3 在触发事件之前需要定义事件。同样在 vue3 中 defineEmits 也是全局 API

  • js 中使用
const emits = defineEmits(["change", "input"]);
emits("chage", "data");
emits("input",  data: 123 );
  • TS 中使用
enum EventName 
  CHANGE = "change",
  INPUT = "input",


const emits = defineEmits<
  (event: EventName.CHANGE, data: string[]): void;
  (event: EventName.INPUT, data: string): void;
>();

emits(EventName.CHANGE, ["data"]);
emits(EventName.INPUT, "123");

上面的代码中使用了枚举 enum 避免"魔法字符串"的出现。值得一提,ts 中也可以使用 js 的方式使用,那么就没有发挥出‘T’的作用。

尤其在大型项目里面触发数据的类型可能会出现意想不到的 bug,然后定位 bug 可能得花上好几个小时。也可能会出现触发事件的事件名字符串写错(俗称魔法字符串)导致达不到预期效果。

总结

经过上述代码示例,可能觉得 ts 的写法似乎更加麻烦了,不如 js 来的快。但是,我个人认为使用 ts 开发不仅仅是提示友好,而且能有效避开很多的坑。可谓:"未雨绸缪"胜过“亡羊补牢”的好。

最后,需要这篇文有帮到你。如有谬误,不吝赐教

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

【中文标题】Vue 3 使用 v-model 作为 props 而不是 :prop 和 @emit【英文标题】:Vue 3 using v-model as props instead of :prop and @emit 【发布时间】:2021-09-04 01:17:56 【问题描述】:

所以我已经阅读了几次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 事件,反过来,它应该被父组件捕获并用于更新父组件的本地状态。

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

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

还有以下错误:

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

我哪里错了?提前致谢。

【问题讨论】:

【参考方案1】:

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

<ChildComponent v-model:documents="user.documents" />

当 ChildComponent 中的文档属性值发生更改时,将自动发出 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>

【讨论】:

以上是关于vue3 中使用 props, emits 并指定其类型与默认值的主要内容,如果未能解决你的问题,请参考以下文章

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

vue3源码分析-实现props,emit,事件处理等

vue3源码分析——实现props,emit,事件处理等

vue3源码分析——实现props,emit,事件处理等

vue3源码分析——实现props,emit,事件处理等

Vue3组件通讯六种方式