Vue 3 中,defineProps<script setup> 语法糖中定义 组件 props 的专用函数。
它让你可以在 组合式 API 下更简洁地声明父组件传入的参数。


🔹 一、基本语法

&lt;script setup>
const props = defineProps({
  title: String,
  count: {
    type: Number,
    required: true,
    default: 0
  }
})
&lt;/script>

&lt;template>
  &lt;h2>{{ title }}&lt;/h2>
  &lt;p>数量:{{ count }}&lt;/p>
&lt;/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 或希望获得智能提示:

&lt;script setup lang="ts">
interface Props {
  name: string
  age?: number
}

const props = defineProps&lt;Props>()
&lt;/script>

或使用 JSDoc(不写 TypeScript):

&lt;script setup>
/** @type {{ name: string, age?: number }} */
const props = defineProps()
&lt;/script>

💡 这种方式在开发中非常常见,因为它更简洁且有类型推断。


🔹 三、结合默认值使用 withDefaults

当使用类型定义(如上)时,默认值不能直接写在类型里
你可以用 withDefaults() 来设置:

&lt;script setup lang="ts">
interface Props {
  name: string
  age?: number
}

const props = withDefaults(defineProps&lt;Props>(), {
  age: 20
})
&lt;/script>

&lt;template>
  &lt;p>{{ name }} - {{ age }}&lt;/p>
&lt;/template>


🔹 四、使用 Props 的注意事项

  1. Props 是只读的 props.name = 'new' // ❌ 不允许修改 如果你要修改它,需先复制: const name = ref(props.name)
  2. 可以在模板中直接使用
    不需要写 props.xxx<template> <h2>{{ title }}</h2> </template>
  3. 与 defineEmits 一起使用 <script setup> const props = defineProps<{ count: number }>() const emit = defineEmits(['update']) const add = () => emit('update', props.count + 1) </script>

🔹 五、完整示例

父组件:

&lt;template>
  &lt;ChildComponent title="Hello Vue3" :count="10" />
&lt;/template>

&lt;script setup>
import ChildComponent from './ChildComponent.vue'
&lt;/script>

子组件:ChildComponent.vue

&lt;script setup>
const props = defineProps({
  title: String,
  count: Number
})
&lt;/script>

&lt;template>
  &lt;h3>{{ title }} - {{ count }}&lt;/h3>
&lt;/template>


🔹 六、进阶:结合解构

可以直接从 props 解构(注意保持响应性):

&lt;script setup>
const { title, count } = defineProps(['title', 'count'])
&lt;/script>

⚠️ 这种方式只在 props 名称简单时使用。
如果要保持响应性(如响应父组件更新),最好不要直接结构复杂对象。


✅ 总结速查表

功能用法示例
定义 propsdefineProps()const props = defineProps({ msg: String })
使用类型defineProps<Type>()const props = defineProps<{ name: string }>()
设置默认值withDefaults()withDefaults(defineProps<{ age?: number }>(), { age: 20 })
直接使用模板中可直接用<p>{{ msg }}</p>
搭配 emitsdefineEmits()const emit = defineEmits(['click'])

很好 👍
下面是一个完整、可运行的 Vue 3 父子组件交互示例项目,展示如何使用:

  • defineProps(定义 props)
  • defineEmits(定义自定义事件)
  • withDefaults(设置默认值)
  • ✅ 父组件向子组件传值
  • ✅ 子组件向父组件发事件更新数据

📂 项目结构

src/
 ├── App.vue               # 父组件
 └── components/
       └── Counter.vue     # 子组件


🧩 1. App.vue(父组件)

&lt;template>
  &lt;div class="p-6 text-center">
    &lt;h1>🎯 defineProps &amp; defineEmits 示例&lt;/h1>
    &lt;p class="text-gray-600">当前计数:{{ count }}&lt;/p>

    &lt;!-- 向子组件传递 props,并监听子组件发出的事件 -->
    &lt;Counter :count="count" title="子组件计数器" @update-count="count = $event" />
  &lt;/div>
&lt;/template>

&lt;script setup>
import { ref } from 'vue'
import Counter from './components/Counter.vue'

// 父组件自己的状态
const count = ref(0)
&lt;/script>

&lt;style scoped>
h1 {
  color: #42b983;
  margin-bottom: 10px;
}
&lt;/style>


🧮 2. components/Counter.vue(子组件)

&lt;template>
  &lt;div class="border rounded-xl shadow-md p-4 w-64 mx-auto mt-4">
    &lt;h2 class="text-lg font-semibold mb-2">{{ title }}&lt;/h2>
    &lt;p class="text-xl font-bold text-blue-600 mb-3">计数:{{ count }}&lt;/p>

    &lt;button @click="add" class="bg-blue-500 text-white px-3 py-1 rounded-md hover:bg-blue-600">
      ➕ 增加
    &lt;/button>
    &lt;button @click="reset" class="ml-2 bg-gray-400 text-white px-3 py-1 rounded-md hover:bg-gray-500">
      ♻️ 重置
    &lt;/button>
  &lt;/div>
&lt;/template>

&lt;script setup lang="ts">
interface Props {
  title?: string
  count: number
}

// ✅ 使用 withDefaults 给 title 设置默认值
const props = withDefaults(defineProps&lt;Props>(), {
  title: '默认计数器'
})

// ✅ 定义事件(子组件 → 父组件)
const emit = defineEmits&lt;{
  (e: 'update-count', value: number): void
}>()

// 事件处理函数
const add = () => emit('update-count', props.count + 1)
const reset = () => emit('update-count', 0)
&lt;/script>

&lt;style scoped>
button {
  transition: 0.2s;
}
&lt;/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

浏览器中打开后,你会看到一个带加号和重置按钮的计数器组件。
点击按钮即可看到父子组件数据同步更新。