
defineProps是 Vue 3 组合式 API (script setup语法糖)中用于声明组件 Props 的编译时宏(Compiler Macro)。它的核心作用是让组件明确接收来自父组件的输入参数(Props),并自动处理 Prop 的响应式绑定、类型校验与默认值。
一、基础概念
-
适用场景 :仅在
<script setup>中使用(Vue 3.2+ 支持),无需手动导入(编译器会自动识别)。 -
本质 :返回一个只读的响应式对象 ,包含父组件传递的所有 Props(修改 Props 会触发警告,需通过
emit反向通信)。 -
单向数据流:Props 是"父传子"的单向绑定,子组件不能直接修改 Props,需通过事件通知父组件更新。
二、核心用法
defineProps支持三种声明方式,覆盖从简单到复杂的场景:
1. 数组语法(简单类型)
适用于仅需声明 Prop 名称的场景(无类型校验、默认值或验证):
javascript
<script setup>
// 声明两个 Prop:title(字符串)、count(数字)
const props = defineProps(['title', 'count'])
</script>
<template>
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
</template>
2. 对象语法(带配置项)
适用于需要类型校验、默认值、必填性、自定义验证的场景。对象键为 Prop 名,值为配置对象:
javascript
<script setup>
const props = defineProps({
// 基础类型校验(支持 String/Number/Boolean/Array/Object/Date/Function/Symbol)
title: {
type: String, // 类型(可多个,如 [String, Number])
required: true, // 是否必填
default: 'Default Title' // 默认值(仅当 required: false 时有效)
},
// 引用类型默认值需用「工厂函数」返回(避免多实例共享同一引用)
list: {
type: Array,
default: () => [] // 工厂函数返回新数组
},
// 自定义验证函数(返回 true 表示合法)
status: {
validator(value) {
return ['active', 'inactive'].includes(value)
}
}
})
</script>
配置项说明:
| 选项 | 类型 | 说明 |
|---|---|---|
type |
原生构造函数/数组 | 校验 Prop 类型(如 String、Number,或多类型 [String, Number]) |
required |
Boolean | 是否为必填 Prop |
default |
任意值/工厂函数 | 默认值(引用类型必须用工厂函数返回,避免共享) |
validator |
Function | 自定义验证函数(参数为 Prop 值,返回布尔值) |
3. TypeScript 类型注解(推荐)
若项目使用 TypeScript,类型注解 是最简洁且类型安全的方式(替代对象语法的类型校验)。需配合 defineProps的泛型参数使用:
TypeScript
<script setup lang="ts">
// 声明 Props 类型(? 表示可选)
interface Props {
title?: string
count: number
list?: string[]
}
// 用泛型传入类型
const props = defineProps<Props>()
</script>
添加默认值:
若需给 TS 类型的 Prop 设置默认值,需配合 withDefaults辅助函数(Vue 3.2+ 支持):
TypeScript
<script setup lang="ts">
interface Props {
title?: string
count?: number
list?: string[]
}
// withDefaults 接收 defineProps 的结果 + 默认值对象
const props = withDefaults(defineProps<Props>(), {
title: 'Hello Vue',
count: 0,
list: () => ['a', 'b'] // 引用类型仍需工厂函数
})
</script>
三、关键特性
1. 响应式访问
defineProps返回的对象是响应式的,可直接在模板或脚本中使用:
javascript
<script setup>
const props = defineProps({ msg: String })
console.log(props.msg) // 响应式值(父组件修改时会更新)
</script>
⚠️ 注意 :不要直接解构 Props (会丢失响应性)!若需解构,需用 toRefs或 toRef转换:
javascript
<script setup>
import { toRefs, toRef } from 'vue'
const props = defineProps({ msg: String, count: Number })
// 正确:保持响应性
const { msg } = toRefs(props)
const countRef = toRef(props, 'count')
// 错误:直接解构会失去响应性
// const { msg, count } = props
</script>
2. 动态 Props
父组件传递的 Prop 若为响应式数据 (如 ref/reactive),子组件通过 defineProps接收后会自动同步更新:
javascript
<!-- 父组件 -->
<script setup>
import { ref } from 'vue'
const parentMsg = ref('Hello from Parent')
</script>
<template>
<Child :msg="parentMsg" />
<button @click="parentMsg = 'Updated'">Change</button>
</template>
<!-- 子组件 -->
<script setup>
const props = defineProps({ msg: String })
</script>
<template>
<p>{{ msg }}</p> <!-- 点击按钮后会更新为 "Updated" -->
</template>
3. 透传 Attributes(v-bind="$attrs")
未被 defineProps声明的 Prop 会被归为透传 Attributes (如 class、style或自定义未声明的 Prop),可通过 $attrs访问或自动绑定到根元素:
javascript
<script setup>
defineProps(['title']) // 仅声明 title
</script>
<template>
<!-- 未声明的 Prop(如 class、data-id)会自动绑定到 div -->
<div class="box" data-id="123">{{ title }}</div>
</template>
若需手动控制透传,可使用 useAttrs()(组合式 API):
javascript
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs() // 包含所有透传 Attributes
</script>
四、常见误区与最佳实践
-
不要在非
<script setup>中使用 :defineProps是script setup的专属宏,普通<script>需用export default { props: {} }(Vue 2 风格)。 -
引用类型默认值必须用工厂函数 :如
default: () => ({})而非default: {}(否则所有组件实例共享同一对象)。 -
优先用 TypeScript 类型注解:比对象语法更简洁,且能享受 TS 的类型提示与校验。
-
避免直接修改 Props :如需修改,应通过
emit触发父组件的事件(如@update:count="val => count = val")。
五、与 Vue 2 的区别
Vue 2 中用 export default { props: {} }声明 Props,而 Vue 3 的 defineProps是编译时优化(无运行时开销),且更贴合组合式 API 的风格。
总结
defineProps是 Vue 3 组件通信的核心工具之一,通过简洁的语法实现了类型安全 、响应式绑定 与灵活的校验配置。

惠州大亚湾