Vue笔记(九)--defineEmits

这一节了解一下Vue3中的defineEmits,defineEmits 是Vue 3.2+引入的编译器宏,仅在<script setup>语法糖中使用,无需从vue导入。 它替代了Options API中的emits选项,返回一个emit函数用于触发事件,简单总结如下:

API:

TypeScript 复制代码
数组语法

<script setup>
const emit = defineEmits(['submit', 'close', 'update:modelValue'])
</script>
TypeScript 复制代码
TypeScript泛型语法

<script setup lang="ts">
const emit = defineEmits<{
  (e: 'submit', payload: { email: string }): void
  (e: 'close'): void
  (e: 'update:modelValue', value: string): void
}>()
// Vue 3.3+ 更简洁写法
const emit = defineEmits<{
  submit: [payload: { email: string }]
  close: []
  'update:modelValue': [value: string]
}>()
</script>

场景:

1 父子组件通信:子组件触发事件通知父组件,如表单提交、列表项删除。

2 自定义v-model双向绑定:子组件接收modelValue prop并触发update:modelValue事件。

3 弹窗/模态框状态通知:子组件触发open/close事件通知父组件控制显隐。

栗子:

TypeScript 复制代码
ChildEmit.vue

<template>
  <div class="child">
    <p>子组件内部数字:{{ innerNum }}</p>
    <button @click="handleAdd">+1,通知父组件</button>
    <button @click="handleClose">关闭弹窗</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const emit = defineEmits<{
  'update:num': [val: number]
  close: []
}>()

const innerNum = ref(0)
const handleAdd = () => {
  innerNum.value++
  emit('update:num', innerNum.value)
}

const handleClose = () => {
  emit('close') // 触发close事件,无参数
}
</script>
TypeScript 复制代码
父组件 ParentEmit.vue

<template>
  <div>
    <h2>父组件,接收子组件事件</h2>
    <p>父拿到的值:{{ parentNum }}</p>
    <ChildEmit @update:num="onUpdateNum" @close="onClose" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import ChildEmit from './ChildEmit.vue'

const parentNum = ref(0)

const onUpdateNum = (val: number) => {
  parentNum.value = val
  console.log('子传过来的新数字:', val)
}

const onClose = () => {
  alert('子组件触发关闭事件')
}
</script>

栗子2

TypeScript 复制代码
子组件 MyDialog.vue

<template>
  <div v-if="visible" class="dialog-wrap">
    <div class="dialog">
      <h3>{{ title }}</h3>
      <p>弹窗内容</p>
      <button @click="handleConfirm">确定</button>
      <button @click="handleCancel">取消</button>
    </div>
  </div>
</template>

<script setup lang="ts">
interface DialogProps {
  visible: boolean 
  title: string   
}
const props = defineProps<DialogProps>()

const emit = defineEmits<{
  confirm: []
  cancel: []
}>()

const handleConfirm = () => {
  emit('confirm')
}
const handleCancel = () => {
  emit('cancel')
}
</script>

<style scoped>
.dialog-wrap {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.4);
  display:flex;
  justify-content:center;
  align-items:center;
}
.dialog {
  background:#fff;
  padding:20px;
  border-radius:8px;
}
</style>
TypeScript 复制代码
父组件 ParentDialog.vue

<template>
  <div>
    <button @click="dialogVisible = true">打开弹窗</button>
    <MyDialog :visible="dialogVisible" title="用户编辑弹窗"
              @confirm="onConfirm"
              @cancel="onCancel"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import MyDialog from './MyDialog.vue'

const dialogVisible = ref(false)

const onConfirm = () => {
  alert('点击确定')
  dialogVisible.value = false
}
const onCancel = () => {
  alert('点击取消')
  dialogVisible.value = false
}
</script>

注意:

1 编译器宏不可导入:直接使用即可,import { defineEmits } from 'vue' 会触发警告。

2 必须顶层调用:只能在 <script setup> 顶层作用域调用,不可置于 if、函数或循环内。

3 每个组件仅调用一次。

相关推荐
创世虚拟世界几秒前
把 3D 虚拟世界拉到本地:vibe coding 的手感,是从看见自己那一行改动开始的
javascript·数据库·人工智能·3d·gitee·虚拟现实
夕阳_醉了10 分钟前
花了一天的时间,地板式扫盲了vue3所有API盲点
前端·javascript·vue.js
问心无愧051330 分钟前
[GXYCTF2019]BabyUpload
笔记
专业程序开发源32 分钟前
django视听资源推荐系统16690-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·php·课程设计
http阿拉丁神猫5 小时前
Go语言入门笔记:从基础到开发环境搭建(二)
开发语言·笔记·golang
HRBorderInsight8 小时前
马来西亚人均收入一个月多少钱,个人薪资和家庭收入要分开看
经验分享·笔记
又見山9 小时前
本地 Markdown 与数据主权:你的笔记到底属于谁
笔记·obsidian
撩得Android一次心动11 小时前
Jetpack Compose 知识点整理2【个人用】
android·笔记·学习·kotlin·compose
ShineWinsu11 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
cao233311 小时前
关于 x1 y1 等变量名冲突的指正(校对版)
笔记