Vue中defineProps和defineEmits怎么用 Vue 中 defineProps 和 defineEmits 怎么用一句话总结defineProps 声明组件接收哪些 propsdefineEmits 声明组件能触发哪些事件它们是script setup的编译时宏不需要 import但必须搭配运行时校验和类型标注才能用得稳正文目录defineProps 和 defineEmits 是什么5 大高频场景 代码示例万能兜底Props/Emits 声明模板预防 checklist不再踩坑一句话总结一、defineProps 和 defineEmits 是什么问题背景Vue3script setup语法糖中组件的 props 和 emits 不再通过props/emits选项声明而是用defineProps和defineEmits宏来声明。特性Options APIscript setup 宏声明 propsprops: { ... }defineProps({ ... })声明 emitsemits: [...]defineEmits([...])需要 import不需要不需要编译宏类型标注无支持 TSwithDefaults默认值defaultwithDefaults或运行时default!-- ❌ 错误在 script setup 中手动 import defineProps -- script setup import { defineProps } from vue // ❌ 不需要也不能 import defineProps({ msg: String }) /script二、5 大高频场景 代码示例场景 1基本类型校验 → 运行时声明!-- ✅ 正确运行时声明带类型和默认值 -- script setup const props defineProps({ title: { type: String, required: true }, count: { type: Number, default: 0 }, items: { type: Array, default: () [] // 对象/数组默认值必须用工厂函数 }, callback: { type: Function, default: () () {} } }) /script template h1{{ title }}/h1 p共 {{ count }} 项/p /template!-- ❌ 错误对象默认值直接写对象 -- script setup const props defineProps({ config: { type: Object, default: { theme: dark } // ❌ 每个实例共享同一引用 } }) /script场景 2TypeScript 类型标注 → 泛型声明!-- ✅ 正确TS 泛型声明类型推断完整 -- script setup langts interface Props { title: string count?: number // 可选 items?: string[] } const props definePropsProps() // withDefaults 提供默认值 const props2 withDefaults(definePropsProps(), { count: 0, items: () [默认项] }) /script!-- ❌ 错误运行时声明和泛型声明混用 -- script setup langts // 不能同时用 type 对象和泛型 const props definePropsProps { extra: { type: String, // ❌ 泛型里不能写运行时校验 required: true } }() /script场景 3defineEmits 事件声明 → 带校验!-- ✅ 正确声明事件 校验函数 -- script setup const emit defineEmits({ // 校验函数 submit: (payload) { if (!payload.email.includes()) { console.warn(email 格式不对) return false } return true }, cancel: null // null 表示不校验 }) function handleSubmit() { emit(submit, { email: bossexample.com, name: 老板 }) } /script template form submit.preventhandleSubmit button typesubmit提交/button button clickemit(cancel)取消/button /form /template!-- ❌ 错误没声明 emit直接用 $emitsetup 中没有 $emit -- script setup function handleClick() { $emit(submit, data) // ❌ ReferenceError: $emit is not defined } /script!-- ✅ 正确TS 泛型声明 emits -- script setup langts const emit defineEmits{ (e: submit, payload: { email: string; name: string }): void (e: cancel): void }() /script场景 4v-model 双向绑定 → defineProps defineEmits 配合!-- ✅ 正确自定义组件实现 v-model -- !-- MyInput.vue -- script setup const props defineProps{ modelValue: string }() const emit defineEmits{ (e: update:modelValue, value: string): void }() function onInput(e) { emit(update:modelValue, e.target.value) } /script template input :valuemodelValue inputonInput / /template!-- 父组件使用 -- template MyInput v-modeltext / !-- 等价于 -- MyInput :model-valuetext update:model-valuetext $event / /template!-- ✅ 进阶多个 v-model -- script setup const props defineProps{ modelValue: string title: string }() const emit defineEmits{ (e: update:modelValue, v: string): void (e: update:title, v: string): void }() /script !-- 父组件 -- template MyInput v-modeltext v-model:titletitleText / /template场景 5defineExpose → 暴露方法给父组件 ref!-- ✅ 正确defineExpose 暴露指定方法不暴露内部实现 -- !-- ChildForm.vue -- script setup import { ref } from vue const formData ref({ name: , age: 0 }) // 内部方法不暴露 function validate() { return formData.value.name.length 0 } // 只暴露需要的方法 defineExpose({ validate, getData: () formData.value, reset: () { formData.value { name: , age: 0 } } }) /script!-- 父组件 -- script setup import { ref, onMounted } from vue import ChildForm from ./ChildForm.vue const formRef ref() function handleSubmit() { if (formRef.value?.validate()) { const data formRef.value.getData() console.log(data) } } /script template ChildForm refformRef / button clickhandleSubmit提交/button /template!-- ❌ 错误没 defineExpose父组件 ref 拿不到任何东西 -- script setup function validate() { return true } // 忘了 defineExpose // 父组件 formRef.value.validate → undefined /script三、万能兜底Props/Emits 声明模板场景推荐写法简单项目运行时声明defineProps({ x: String })TS 项目泛型声明definePropsProps()withDefaults事件校验defineEmits({ submit: (p) true })v-modelmodelValueprop update:modelValueemit多 v-model命名 v-modelv-model:title暴露方法defineExpose({ method })万能模板script setup langts import { computed } from vue // 1. Props 泛型 默认值 interface Props { modelValue: string title?: string items?: string[] disabled?: boolean } const props withDefaults(definePropsProps(), { title: 默认标题, items: () [], disabled: false }) // 2. Emits 泛型声明 const emit defineEmits{ (e: update:modelValue, v: string): void (e: submit, payload: { value: string }): void (e: cancel): void }() // 3. computed 代理 v-model const innerValue computed({ get: () props.modelValue, set: (v) emit(update:modelValue, v) }) // 4. defineExpose 暴露方法 defineExpose({ focus: () {}, reset: () {} }) /script四、预防 checklist不再踩坑不要 import defineProps / defineEmits它们是编译宏对象/数组类型的 default 用工厂函数() ({})/() []script setup中没有this不能用this.$emit必须用 defineEmits 返回的 emit声明了 emits 的事件不会出现在$attrs上不会被当原生事件v-model 的 prop 名叫modelValue事件名叫update:modelValue多个 v-model 用具名 modelv-model:titletitleTextTS 项目优先用泛型声明 withDefaults需要父组件 ref 调用子组件方法时必须defineExposeemit 带校验函数时返回 false 会触发警告但不阻止 emit五、一句话总结defineProps 声明接收、defineEmits 声明触发、defineExpose 声明暴露——三个编译宏撑起script setup的组件 API搭配 TS 泛型和 withDefaults 才是完整形态。最后问候亲爱的朋友们并邀请你们阅读我的全新著作 《Vue.js 3企业级项目开发实战微课视频版》