【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 暴露组件内部成员(属性 / 方法) 父组件直接访问子组件内部状态
相关推荐
我的名字帅不帅5 小时前
使用 Element UI -Container 布局容器时监听屏幕滚动无效
vue.js
霍格沃兹_测试5 小时前
软件测试 | 测试开发 | H5页面多端兼容测试与监控
前端
用户28003832908405 小时前
升级Vue3.4+版本,ant-design-vue 3.x 版本的Modal函数方式无法关闭问题
vue.js
toooooop85 小时前
本地开发环境webScoket调试,保存html即用
前端·css·websocket
山有木兮木有枝_5 小时前
手动封装移动端下拉刷新组件的设计与实现
前端
阳光阴郁大boy5 小时前
大学信息查询平台:一个现代化的React教育项目
前端·react.js·前端框架
小菜全6 小时前
uniapp新增页面及跳转配置方法
开发语言·前端·javascript·vue.js·前端框架
AlexMercer10126 小时前
[前端]1.html基础
前端·笔记·学习·html
白水清风6 小时前
关于Js和Ts中类(class)的知识
前端·javascript·面试