defineProps 是 Vue 3 setup 语法糖中声明和接收 props 的标准方式,需顶层同步调用;支持运行时对象声明和 TypeScript 泛型声明;props 响应式但不可直接解构,应通过 toRefs 或 computed 访问;监听需用 watch 函数,父组件传值须注意 kebab-case 与 camelCase 转换。

在 Vue 3 的 setup 语法糖中,defineProps 是声明和接收父组件传入 props 的标准方式。它必须在 setup 顶层同步调用,不能在条件语句或函数内部使用。
基础用法:声明 props 类型与默认值
使用 defineProps 可以传入一个对象(运行时声明)或泛型类型(推荐,配合 TypeScript 或 Volar 支持):
-
运行时声明(JS 项目常用):
<script setup>
const props = defineProps({
title: { type: String, default: '默认标题' },
count: { type: Number, default: 0 },
isActive: { type: Boolean, default: false }
})
</script> -
类型声明(TS 推荐):
<script setup lang="ts">
interface Props {
title?: string
count: number
isActive: boolean
}
const props = defineProps<Props>()
</script>
此时 TypeScript 能提供完整类型推导和 IDE 提示,未设默认值的可选属性需加?或在接口中用default配合运行时对象写法。
响应式访问与解构注意事项
props 是响应式的,但直接解构会丢失响应性(如 const { title } = props),修改后视图不会更新。正确做法是:
- 始终通过
props.xxx访问; - 如需解构且保持响应性,用
toRefs(props):
import { toRefs } from 'vue'
const { title, count } = toRefs(props)(注意此时title.value才是真实值); - 更简洁的替代:用
computed封装派生属性,例如:
const displayTitle = computed(() => props.title || '无标题')。
处理 props 更新与监听
props 变化时,不能直接监听 props 对象本身,但可以:
- 监听单个 prop:
watch(() => props.count, (newVal, oldVal) => { ... }); - 监听多个 prop(用数组):
watch([() => props.title, () => props.count], ([newT, newC], [oldT, oldC]) => { ... }); - 若需在 props 变化时执行副作用(如请求数据),推荐在
watch中处理,而非onUpdated—— 后者触发时机更宽泛,不专属于 props 变化。
父组件传参写法对应说明
确保父组件正确传值,才能被 defineProps 正确接收:
- 静态值:
<Child title="首页" :count="5" :is-active="true" />; - 动态绑定(必用
v-bind或简写:):<Child :title="pageTitle" :count="pageCount" />; - 注意命名规范:HTML 中用 kebab-case(
is-active),JS 中自动转为 camelCase(props.isActive)。


















