Vue 3 中 <script setup>
使用 Props 指南
问题描述
在 Vue 3 的 <script setup>
语法糖中,很多开发者不清楚如何正确声明和使用 props。在传统的 Options API 中,我们使用 props
选项来定义组件属性,但在 Composition API 的 <script setup>
中,需要使用不同的方法。
原问题中的代码示例展示了常见的困惑:
html
<script setup>
import TopNavbar from '@/layout/TopNavbar.vue'
import { defineProps, reactive } from 'vue'
defineProps({
no: String
})
const init = async () => {
// 如何在这里使用 props?
// const { data } = await getRoomByNo(props.no)
}
</script>
解决方案
基础用法:声明和使用 Props
在 <script setup>
中,使用 defineProps()
宏来声明组件属性:
html
<script setup>
import { defineProps } from 'vue'
// 声明 props
const props = defineProps({
no: String,
// 更多属性定义
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
})
// 在代码中使用 props
console.log(props.no)
console.log(props.title)
</script>
在异步函数中使用 Props
要解决原始问题中的异步函数使用 props 的场景:
html
<script setup>
import { defineProps, reactive } from 'vue'
const props = defineProps({
no: String
})
const state = reactive({
room: {}
})
const init = async () => {
// 正确使用 props.no
const { data } = await getRoomByNo(props.no)
console.log(data)
state.room = data
}
init()
</script>
使用 toRefs 保持响应性
TIP
如果需要保持 props 的响应性,可以使用 toRefs
进行解构:
html
<script setup>
import { defineProps, toRefs } from 'vue'
const props = defineProps({
no: String,
myIdOfSomething: Number
})
const { no, myIdOfSomething } = toRefs(props)
console.log(no.value) // 使用 .value 访问
console.log(myIdOfSomething.value)
</script>
TypeScript 支持
基本类型定义
对于 TypeScript 用户,可以使用类型注解来获得更好的类型安全:
html
<script setup lang="ts">
interface Props {
no: string
disabled: boolean
loading?: boolean
}
const props = defineProps<Props>()
</script>
带默认值的类型定义
WARNING
使用类型注解方式时,如果需要默认值,必须使用 withDefaults
辅助函数。
html
<script setup lang="ts">
interface Props {
disabled: boolean
loading: boolean
bordered: boolean
label?: string
}
const props = withDefaults(defineProps<Props>(), {
label: "Button Label",
})
</script>
替代方案:选项式类型定义
另一种在 TypeScript 中定义 props 的方式:
html
<script setup lang="ts">
import { PropType } from 'vue'
const props = defineProps({
color: {
type: String as PropType<'primary'|'info'|'success'|'error'|'warning'>,
default: 'primary'
}
})
</script>
完整示例
子组件 CircleImage.vue
html
<template>
<div class="px-4 w-8/12 sm:w-3/12">
<img :src="src" :alt="alt" class="border-none rounded-full h-auto max-w-full align-middle" />
</div>
</template>
<script setup>
const props = defineProps({
src: String,
alt: String,
})
</script>
父组件 MyView.vue
html
<template>
<div class="flex flex-wrap justify-center">
<CircleImage src="/file1.jpg" alt="one" />
<CircleImage src="/file2.svg" alt="two" />
</div>
</template>
<script setup>
import CircleImage from '@/components/CircleImage.vue'
</script>
注意事项
- 自动导入:
defineProps
和withDefaults
在<script setup>
中自动可用,无需显式导入 - 响应性:通过
defineProps
声明的 props 已经是响应式的 - 默认值:在非 TypeScript 环境下,可以直接在选项对象中定义默认值
- 只读性:Props 是只读的,不应在子组件中直接修改
总结
Vue 3 的 <script setup>
语法提供了简洁的 props 声明方式:
- 使用
defineProps()
宏声明 props - 对于 TypeScript,可以使用类型注解增强类型安全
- 需要默认值时,使用
withDefaults()
辅助函数 - 保持响应性可使用
toRefs()
解构 props
这种方法使得组件代码更加简洁,同时保持了完整的类型支持和响应性特性。