在 Vue 3 中,defineProps
是 <script setup>
语法糖中定义 组件 props 的专用函数。
它让你可以在 组合式 API 下更简洁地声明父组件传入的参数。
🔹 一、基本语法
<script setup>
const props = defineProps({
title: String,
count: {
type: Number,
required: true,
default: 0
}
})
</script>
<template>
<h2>{{ title }}</h2>
<p>数量:{{ count }}</p>
</template>
✅ 说明:
defineProps()
是编译器宏,不需要导入;- 在
<script setup>
中直接使用; - 返回一个响应式对象(
props
),可以直接使用; - 不能在运行时调用,必须在顶层调用。
🔹 二、两种定义方式
✅ 方式 1:对象语法(推荐)
用于声明类型、默认值和是否必需:
const props = defineProps({
name: String,
age: {
type: Number,
default: 18,
},
isActive: {
type: Boolean,
required: true,
}
})
这与 Vue 2 的 props 定义语法几乎一样。
✅ 方式 2:使用 TypeScript 类型(或 JSDoc)
如果你使用 TypeScript 或希望获得智能提示:
<script setup lang="ts">
interface Props {
name: string
age?: number
}
const props = defineProps<Props>()
</script>
或使用 JSDoc(不写 TypeScript):
<script setup>
/** @type {{ name: string, age?: number }} */
const props = defineProps()
</script>
💡 这种方式在开发中非常常见,因为它更简洁且有类型推断。
🔹 三、结合默认值使用 withDefaults
当使用类型定义(如上)时,默认值不能直接写在类型里。
你可以用 withDefaults()
来设置:
<script setup lang="ts">
interface Props {
name: string
age?: number
}
const props = withDefaults(defineProps<Props>(), {
age: 20
})
</script>
<template>
<p>{{ name }} - {{ age }}</p>
</template>
🔹 四、使用 Props 的注意事项
- Props 是只读的
props.name = 'new' // ❌ 不允许修改
如果你要修改它,需先复制:const name = ref(props.name)
- 可以在模板中直接使用
不需要写props.xxx
:<template> <h2>{{ title }}</h2> </template>
- 与 defineEmits 一起使用
<script setup> const props = defineProps<{ count: number }>() const emit = defineEmits(['update']) const add = () => emit('update', props.count + 1) </script>
🔹 五、完整示例
父组件:
<template>
<ChildComponent title="Hello Vue3" :count="10" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
</script>
子组件:ChildComponent.vue
<script setup>
const props = defineProps({
title: String,
count: Number
})
</script>
<template>
<h3>{{ title }} - {{ count }}</h3>
</template>
🔹 六、进阶:结合解构
可以直接从 props 解构(注意保持响应性):
<script setup>
const { title, count } = defineProps(['title', 'count'])
</script>
⚠️ 这种方式只在 props 名称简单时使用。
如果要保持响应性(如响应父组件更新),最好不要直接结构复杂对象。
✅ 总结速查表
功能 | 用法 | 示例 |
---|---|---|
定义 props | defineProps() | const props = defineProps({ msg: String }) |
使用类型 | defineProps<Type>() | const props = defineProps<{ name: string }>() |
设置默认值 | withDefaults() | withDefaults(defineProps<{ age?: number }>(), { age: 20 }) |
直接使用 | 模板中可直接用 | <p>{{ msg }}</p> |
搭配 emits | defineEmits() | const emit = defineEmits(['click']) |
很好 👍
下面是一个完整、可运行的 Vue 3 父子组件交互示例项目,展示如何使用:
- ✅
defineProps
(定义 props) - ✅
defineEmits
(定义自定义事件) - ✅
withDefaults
(设置默认值) - ✅ 父组件向子组件传值
- ✅ 子组件向父组件发事件更新数据
📂 项目结构
src/
├── App.vue # 父组件
└── components/
└── Counter.vue # 子组件
🧩 1. App.vue(父组件)
<template>
<div class="p-6 text-center">
<h1>🎯 defineProps & defineEmits 示例</h1>
<p class="text-gray-600">当前计数:{{ count }}</p>
<!-- 向子组件传递 props,并监听子组件发出的事件 -->
<Counter :count="count" title="子组件计数器" @update-count="count = $event" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import Counter from './components/Counter.vue'
// 父组件自己的状态
const count = ref(0)
</script>
<style scoped>
h1 {
color: #42b983;
margin-bottom: 10px;
}
</style>
🧮 2. components/Counter.vue(子组件)
<template>
<div class="border rounded-xl shadow-md p-4 w-64 mx-auto mt-4">
<h2 class="text-lg font-semibold mb-2">{{ title }}</h2>
<p class="text-xl font-bold text-blue-600 mb-3">计数:{{ count }}</p>
<button @click="add" class="bg-blue-500 text-white px-3 py-1 rounded-md hover:bg-blue-600">
➕ 增加
</button>
<button @click="reset" class="ml-2 bg-gray-400 text-white px-3 py-1 rounded-md hover:bg-gray-500">
♻️ 重置
</button>
</div>
</template>
<script setup lang="ts">
interface Props {
title?: string
count: number
}
// ✅ 使用 withDefaults 给 title 设置默认值
const props = withDefaults(defineProps<Props>(), {
title: '默认计数器'
})
// ✅ 定义事件(子组件 → 父组件)
const emit = defineEmits<{
(e: 'update-count', value: number): void
}>()
// 事件处理函数
const add = () => emit('update-count', props.count + 1)
const reset = () => emit('update-count', 0)
</script>
<style scoped>
button {
transition: 0.2s;
}
</style>
🧠 工作原理
动作 | 说明 |
---|---|
父组件通过 :count 把值传入子组件 | 子组件用 defineProps 接收 |
子组件点击按钮时触发 emit('update-count', 新值) | 触发自定义事件 |
父组件监听 @update-count | 更新父组件的 count |
Vue 自动触发响应式更新 | 父、子组件 UI 同步刷新 |
⚙️ 3. 运行步骤
在你的项目目录中:
# 创建项目
npm create vue@latest my-vue3-demo
cd my-vue3-demo
# 安装依赖
npm install
# 运行项目
npm run dev
然后将上面两个文件分别替换项目中的:
src/App.vue
src/components/Counter.vue
浏览器中打开后,你会看到一个带加号和重置按钮的计数器组件。
点击按钮即可看到父子组件数据同步更新。
发表回复