defineEmits 简要介绍

📋 一句话概括

defineEmitsVue 3 组合式 API 中定义 组件事件 的 编译时宏,用于 声明组件 可以 触发 哪些事件

🎯 核心作用

替代 Vue 2 的 emits 选项,在 <script setup> 中声明组件事件。

📝 基本语法

<script setup>
// 定义 emits
const emit = defineEmits<{
  (e: '事件名', 参数1, 参数2, ...): void
}>()

// 触发事件
emit('事件名', 参数值)
</script>

🔧 三种写法

1. TypeScript 类型 字面量 写法(推荐) ★

const emit = defineEmits<{
  (e: 'submit', data: FormData): void
  (e: 'cancel'): void
  (e: 'update:value', value: string): void
}>()

2. 运行时声明(JavaScript)

const emit = defineEmits(['submit', 'cancel', 'update:value'])

3. TypeScript 接口式写法

interface Emits {
  (e: 'submit', data: any): void
  (e: 'cancel'): void
}

const emit = defineEmits<Emits>()

主要特点

优点

  • 类型安全:完整的 TypeScript 支持
  • 智能提示:IDE 提供事件名自动补全
  • 参数验证:编译时检查参数类型
  • v-model 支持:支持 update:xxx 双向绑定语法

限制

  • 编译时宏:只能在 <script setup> 中使用
  • 只读emit 函数是只读的

🔄 与 Vue 2 对比

特性 Vue 2 (选项式) Vue 3 (组合式)
定义位置 emits 选项 defineEmits
类型支持 有限 完整的 TypeScript
语法 相对冗长 简洁
事件验证 运行时 编译时

📦 实际示例

<!-- 子组件 Child.vue -->
<script setup lang="ts">
// 定义事件
const emit = defineEmits<{
  (e: 'submit', data: { name: string, age: number }): void
  (e: 'cancel'): void
  (e: 'update:visible', visible: boolean): void
}>()

// 触发事件
const handleSubmit = () => {
  emit('submit', { name: '张三', age: 25 })
  emit('update:visible', false)
}

const handleCancel = () => {
  emit('cancel')
  emit('update:visible', false)
}
</script>

<template>
  <button @click="handleSubmit">提交</button>
  <button @click="handleCancel">取消</button>
</template>

<!-- 父组件使用 -->
<template>
  <Child 
    @submit="handleSubmit"
    @cancel="handleCancel"
    v-model:visible="modalVisible"
  />
</template>

🎯 v-model 双向绑定

// 子组件定义
const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
}>()

// 父组件使用
<ChildComponent v-model="value" />
// 等价于
<ChildComponent :modelValue="value" @update:modelValue="value = $event" />

💡 常见使用场景

  1. 表单提交@submit 事件传递表单数据
  2. 模态框控制@close@confirm 事件
  3. 数据变更@change@input 事件
  4. 操作反馈@success@error 事件
  5. 双向绑定update:xxx 实现 v-model

⚠️ 注意事项

  1. 事件名使用 kebab-case(HTML 中自动转换)
  2. 组件内部不能修改 emit 函数
  3. 使用 TypeScript 获得完整类型提示
  4. 复杂参数建议定义接口类型

🎓 记住这几点

  1. 只在 <script setup> 中使用
  2. 触发事件用 emit('事件名', 参数)
  3. TypeScript 能提供完整类型检查
  4. 支持 v-model 双向绑定语法

这就是 defineEmits 的核心要点!它是 Vue 3 组件通信的重要工具,让事件定义更加类型安全和规范。