【Vue】defineProps、defineEmits 和 defineExpose

一、概念

在 Vue3 的 <script setup> 语法糖中,definePropsdefineEmitsdefineExpose 是三个核心 API,用于处理组件的属性接收事件触发内部成员暴露,是组件通信和封装的基础。

二、说明

defineProps :声明组件接收的 props

用于在组件中声明可以从父组件接收的属性(props) ,相当于选项式 API 中的 props 选项。

  • 特点 :无需导入,直接在 <script setup> 中使用;返回一个包含接收 props 的对象,可通过该对象访问 props 的值。
  • 作用:明确组件的输入参数,支持类型校验,提升代码可读性和可维护性。

基本用法

vue 复制代码
<template>
    <div>父组件传递的名称:{{ name }}</div> 
    <div>年龄:{{ age }}</div>
</template> 
<script setup> 
// 1. 简单声明(数组形式,仅指定 prop 名称)
// const props = defineProps(['name', 'age']) 
// 2. 完整声明(对象形式,指定类型、默认值、校验等) 
const props = defineProps({ 
    name: { 
        type: String,// 类型 
        required: true, // 是否必传 
        default: '默认名称' // 默认值(非必传时生效) 
    }, 
    age: { 
        type: Number,
        validator: (value) => { // 自定义校验 
        return value >= 0; 
        // 年龄不能为负数 
       }
      }
    }) 
// 访问 props 的值 
console.log(props.name) // 父组件传递的 name
console.log(props.age) // 父组件传递的 age 
</script>

TypeScript 支持:

可通过泛型指定类型,实现更严格的类型校验:

typescript 复制代码
// TypeScript 写法
const props = defineProps<{ 
    name: string; 
    age?: number; // 可选属性 
}>() 
// 带默认值的 TypeScript 写法(需配合 withDefaults) 
const props = withDefaults(defineProps<{
    name: string; 
    age?: number;
}>(), {
    age: 18 // 默认值
})

defineEmits:声明组件触发的事件

用于在组件中声明可以向父组件触发的事件(emits) ,相当于选项式 API 中的 emits 选项。

  • 特点 :无需导入,直接使用;返回一个 emit 函数,用于触发事件。
  • 作用:明确组件的输出事件,支持事件参数类型校验,避免事件名冲突

基本使用

vue 复制代码
<template> 
    <button @click="handleClick">点击触发事件</button> 
</template> 
<script setup> 
// 1. 简单声明(数组形式,仅指定事件名称) 
// const emit = defineEmits(['change', 'submit'])
// 2. 完整声明(对象形式,指定事件参数类型)
const emit = defineEmits({ 
    // 无参数的事件
    change: () => true, // 校验通过(始终返回 true 表示无校验)
    // 有参数的事件(校验参数是否符合预期)
    submit: (username: string, password: string) => {
        return username && password; // 仅当 username 和 password 都存在时校验通过
    } 
}) 

// 触发事件(通过返回的 emit 函数)
const handleClick = () => {
    emit('change') // 触发无参事件 
    emit('submit', 'admin', '123456') // 触发带参事件 
} 
</script>

TypeScript 支持:

通过泛型指定事件类型,获得更精准的类型提示:

typescript 复制代码
// TypeScript 写法(声明事件名和参数类型) 
const emit = defineEmits<{ 
    (e: 'change'): void; // 无参数事件
    (e: 'submit', username: string, password: string): void; // 带参数事件 
}>() 

// 触发时会有类型提示 
emit('submit', 'admin') // 错误:缺少 password 参数(TypeScript 会报错)

defineExpose:暴露组件内部成员

用于在 <script setup>显式暴露组件的内部属性或方法 ,让父组件可以通过 ref 访问。

  • 背景 :在 <script setup> 中,组件的内部成员(变量、函数)默认是 "私有" 的,父组件无法通过 ref 直接访问。
  • 作用:主动暴露需要被父组件访问的成员,实现父子组件的 "直接通信"(非 props/emits 方式)。
基本语法
Child.vue 复制代码
<!-- 子组件 Child.vue -->
<template> 
    <div>子组件内部值:{{ count }}</div> 
</template> 

<script setup> 
import { ref } from 'vue' 

// 内部状态和方法 const count = ref(0) 
const increment = () => { 
    count.value++
} 

// 暴露给父组件(父组件可通过 ref 访问) 
defineExpose({
    count, 
    increment
}) 
</script>
Parent.vue 复制代码
<!-- 父组件 Parent.vue -->
<template>
    <Child ref="childRef" />
    <button @click="accessChild">访问子组件</button>
</template>
<script setup>
import { ref } from 'vue' 
import Child from './Child.vue'
const childRef = ref(null) 
const accessChild = () => { 
// 通过 ref 访问子组件暴露的成员 
    console.log(childRef.value.count) // 0(访问子组件的 count) 
    childRef.value.increment() // 调用子组件的 increment 方法
} 
</script>

三、总结

API 作用 核心场景
defineProps 声明组件接收的 props 父组件向子组件传递数据
defineEmits 声明组件触发的事件,返回 emit 函数 子组件向父组件传递数据 / 通知
defineExpose 暴露组件内部成员(属性 / 方法) 父组件直接访问子组件内部状态
相关推荐
2601_96377137几秒前
How to Scale Your WordPress Store Traffic in 2026
前端·php·plugin
亿元程序员9 分钟前
老板说我的3D箭头游戏用来做试玩太普通了,没人想玩,让我变点花样...
前端
李伟_Li慢慢1 小时前
01-threejs架构原理-课程简介
前端·three.js
_瑞2 小时前
深入理解 iOS 渲染原理
前端·ios
IT_陈寒2 小时前
SpringBoot自动配置失灵?你可能忘了这个关键注解
前端·人工智能·后端
碎碎念_4922 小时前
SpringBoot + Vue 前后端分离从 0 到 1 完整环境配置流程
vue.js·spring boot·后端
iCOD3R3 小时前
Skill - kill-ai-slop 解决“AI 味”样式
前端·css·ai编程
shuaijie05183 小时前
强制修改调用接口的api地址。
javascript·vue.js·ecmascript
皮音3 小时前
Skill 在项目中的实践 —— 从 Agent 困境到 Skill 工程化
前端
大龄秃头程序员3 小时前
RN 0.86 新架构实战:TurboModule + Fabric 组件 + iOS 原生容器,完整代码开源
前端·react native