在 Vue 3 中,Props 声明有两种主要方式:Options API 中的 props 选项和 Composition API 中的 defineProps 宏。以下是它们的详细对比和使用说明:
一、核心区别
使用场景 | Options API 组件 | <script setup> 组件 |
位置 | 组件选项对象内 | <script setup> 顶层作用域 |
访问方式 | 通过 this 访问 | 通过返回值访问 |
响应性 | 自动响应式 | 自动响应式 |
TypeScript | 需 PropType 辅助 | 原生支持类型推导 |
默认值 | default 属性 | default 属性 或 withDefaults |
编译时 | 运行时声明 | 编译时宏(编译后消失) |
二、props (Options API) 使用详解
export default {
props: {
// 类型声明
title: String,
// 详细配置
count: {
type: Number,
required: true,
validator: value => value >= 0
},
// 带默认值的对象
config: {
type: Object,
default: () => ({ size: 'medium' })
},
// TS 类型支持
book: {
type: Object as PropType<Book>,
default: null
}
},
mounted() {
console.log(this.title) // 通过 this 访问
}
}
三、defineProps (Composition API) 使用详解
1. 基础用法
<script setup>
// 运行时声明 (JS)
const props = defineProps({
title: String,
count: {
type: Number,
required: true
},
tags: {
type: Array,
default: () => []
}
})
console.log(props.title) // 直接访问
</script>
2. TypeScript 类型声明(推荐)
<script setup lang="ts">
// 纯类型声明 (TS)
interface Props {
id: number
title: string
disabled?: boolean
sizes?: string[]
}
const props = defineProps<Props>()
</script>
3. 带默认值的 TS 声明
<script setup lang="ts">
import { withDefaults } from 'vue'
interface Props {
size?: 'sm' | 'md' | 'lg'
labels?: string[]
}
// 提供默认值
const props = withDefaults(defineProps<Props>(), {
size: 'md',
labels: () => ['OK', 'Cancel']
})
</script>
四、关键差异详解
1. 类型系统支持
// Options API (需 PropType)
import type { PropType } from 'vue'
props: {
book: {
type: Object as PropType<Book>, // 需要类型断言
required: true
}
}
// Composition API (直接类型)
defineProps<{ book: Book }>()
2. 默认值处理
// Options API
props: {
items: {
type: Array,
default: () => [] // 必须用工厂函数
}
}
// Composition API (纯TS时)
withDefaults(defineProps<{ items?: string[] }>(), {
items: () => ['default'] // 工厂函数
})
3. 访问方式
<script>
// Options API
export default {
props: ['message'],
methods: {
show() {
console.log(this.message) // 通过 this
}
}
}
</script>
<script setup>
// Composition API
const props = defineProps(['message'])
console.log(props.message) // 直接访问
</script>
五、最佳实践指南
新项目优先选择:
-
使用 <script setup> + defineProps + TypeScript
-
获得更好的类型支持和更简洁的语法
默认值注意事项:
-
对象/数组必须使用工厂函数返回新实例
// ✅ 正确
default: () => [1, 2, 3]
// ❌ 错误(共享引用)
default: [1, 2, 3]
复杂验证:
defineProps({
email: {
validator(value) {
return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)
}
}
})
跨API兼容:
-
Options API 声明的 props 在 Composition API 的 setup() 中可通过参数访问
export default {
props: ['message'],
setup(props) {
console.log(props.message)
}
}
六、高级用法示例
1. 联合类型 + 默认值
<script setup lang="ts">
interface Props {
variant?: 'primary' | 'secondary' | 'text'
}
const { variant = 'primary' } = defineProps<Props>()
</script>
2. 动态 Prop 名称
<script setup>
const dynamicKey = 'dynamicProp'
defineProps({
[dynamicKey]: {
type: String,
default: ''
}
})
</script>
3. 响应式解构(保留响应性)
<script setup>
import { toRefs } from 'vue'
const props = defineProps({ count: Number })
const { count } = toRefs(props) // 保持响应性
</script>
七、核心总结
声明位置 | 组件选项内 | <script setup> 顶层 |
类型支持 | 需 PropType 辅助 | 原生 TS 支持 |
默认值 | default 属性 | withDefaults 或 default |
访问方式 | this.propName | props.propName |
响应性 | 自动响应式 | 自动响应式 |
编译处理 | 运行时校验 | 编译时宏(无运行时开销) |
推荐场景 | 传统 Options API 组件 | 现代 Composition API 组件 |
迁移建议:新项目应优先使用 <script setup> + defineProps,老项目逐步迁移以获得更好的类型支持和开发体验。两者在功能上是等效的,但 Composition API 方式更符合现代 Vue 开发模式。
评论前必须登录!
注册