前言
对于Vue3中的基本知识推荐阅读:
1. 基本知识
defineEmits 是 Vue 3 的组合式 API(Composition API)的一部分,用于在组件中定义和使用自定义事件
它替代了 Vue 2 中的 this.$emit
和 this.$on
,让事件的定义和使用变得更加清晰和类型安全,尤其在 TypeScript 中
defineEmits 的基本用法
-
定义事件:在组件内部通过 defineEmits 定义事件
可以传递一个数组或对象来定义事件名和事件参数 -
触发事件:使用 emit 方法触发定义的事件
-
接收事件:在父组件中使用自定义事件监听器来接收事件
2. Demo
2.1 传值
基本的用法如下:
在子组件中,定义两个事件:increment 和 decrement。当按钮被点击时,相应的事件会被触发
<template>
<div>
<button @click="handleIncrement">Increment</button>
<button @click="handleDecrement">Decrement</button>
</div>
</template>
<script setup lang="ts">
const emit = defineEmits(['increment', 'decrement']);
const handleIncrement = () => {
emit('increment');
};
const handleDecrement = () => {
emit('decrement');
};
</script>
在父组件中,监听子组件触发的 increment 和 decrement 事件,并通过相应的处理函数来更新计数器
<template>
<div>
<p>Counter: {{ counter }}</p>
<ChildComponent @increment="increment" @decrement="decrement" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const counter = ref(0);
const increment = () => {
counter.value++;
};
const decrement = () => {
counter.value--;
};
</script>
2.2 传参
子组件中,定义一个事件 updateValue,它会传递一个数值参数
<template>
<div>
<button @click="update(1)">Increment</button>
<button @click="update(-1)">Decrement</button>
</div>
</template>
<script setup lang="ts">
const emit = defineEmits<{ (e: 'updateValue', value: number): void }>();
const update = (value: number) => {
emit('updateValue', value);
};
</script>
在父组件中,接收 updateValue 事件,并使用传递的参数更新计数器
<template>
<div>
<p>Counter: {{ counter }}</p>
<ChildComponent @updateValue="updateCounter" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const counter = ref(0);
const updateCounter = (value: number) => {
counter.value += value;
};
</script>
2.3 传对象
在对象中,键是事件名,值是一个函数,该函数的参数就是事件的参数
子组件 使用对象语法定义事件和参数类型
<template>
<div>
<button @click="update(1)">Increment</button>
<button @click="update(-1)">Decrement</button>
</div>
</template>
<script setup lang="ts">
const emit = defineEmits({
updateValue: (value: number) => true,
});
const update = (value: number) => {
emit('updateValue', value);
};
</script>
在父组件中,接收 updateValue 事件,并使用传递的参数更新计数器
<template>
<div>
<p>Counter: {{ counter }}</p>
<ChildComponent @updateValue="updateCounter" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const counter = ref(0);
const updateCounter = (value: number) => {
counter.value += value;
};
</script>
3. 实战
先给一个实战的例子:
整体逻辑如下:
-
定义和触发事件
使用 defineEmits([‘success’]) 定义了一个 success 事件
在表单提交成功后,通过 emit(‘success’) 触发 success 事件 -
表单提交逻辑
submitForm 函数负责表单提交逻辑
首先校验表单数据
根据表单类型 (create 或 update) 发起相应的 API 请求
请求成功后,弹出成功消息并关闭表单对话框
最后触发 success 事件,通知父组件刷新列表 -
父组件监听事件
父组件 EnterpriseRegistry 监听子组件 EnterpriseRegistryForm 的 success 事件
在监听到 success 事件后,调用 getList 方法重新获取列表数据
子组件(表单组件)
// 定义和触发 success 事件
const emit = defineEmits(['success']);
const submitForm = async () => {
await formRef.value.validate();
formLoading.value = true;
try {
const data = formData.value as unknown as EnterpriseRegistryVO;
if (formType.value === 'create') {
await EnterpriseRegistryApi.createEnterpriseRegistry(data);
message.success(t('common.createSuccess'));
} else {
await EnterpriseRegistryApi.updateEnterpriseRegistry(data);
message.success(t('common.updateSuccess'));
}
dialogVisible.value = false;
emit('success'); // 触发 success 事件
} finally {
formLoading.value = false;
}
};
父组件:
<EnterpriseRegistryForm ref="formRef" @success="getList" />
对应的方法:
const getList = async () => {
loading.value = true;
try {
const data = await EnterpriseRegistryApi.getEnterpriseRegistryPage(queryParams);
list.value = data.list;
total.value = data.total;
} finally {
loading.value = false;
}
};
对应的逻辑如下:
- defineEmits 定义事件:在子组件中使用 defineEmits 定义事件,事件名可以是字符串数组或对象形式,用于明确事件类型和参数
- emit 触发事件:通过调用 emit 方法触发已定义的事件,并可携带相关参数
- 父组件监听事件:父组件通过 @事件名 监听子组件触发的事件,从而在事件触发时执行相应的处理逻辑