Props声明
Props声明主要有2种方式
- 基于数组的声明
- 基于对象的声明
基于数组的声明
<script setup>
const props = defineProps(['arg1, arg2']);
</script>
基于对象的声明
基于对象的声明提供了更灵活的配置,可配置项包含:
type: 数据类型required: 参数是否必须default: 默认值(对于对象类型,必须使用函数返回对象的默认值)validator: 自定义校验器,返回true/false
<script setup>
const props = defineProps({
title: String, // 指定类型
likes: { // 更细致化的描述
type: Number,
required: true // 默认为false
},
isPublished: {
type: Boolean,
default: false // 默认值为undefined,对于Boolean会转化为false
},
author: {
type: Object,
default: ()=>{ // 必须使用函数返回
name: '匿名',
company: '未知'
}
},
articleType: {
validator: (v)=>{
return ["技术", "人文"].includes(v);
}
}
});
</script>
利用Typescript进行类型指定
<script setup lang="ts">
interface Props{
title: string;
likes: number;
isPublished?: boolean; // ?表示可选
author: {name: string; company: string};
articleType: "技术" | "人文";
} // 或 type Props = {...}
const props = defineProps<Props>();
</script>
Typescript中指定默认值
方法一:withDefaults
<script setup lang="ts">
const props = withDefaults(defineProps<Props>(), {
likes: 0,
isPublished: false,
});
</script>
方法二:Props解构默认值(仅支持v3.5以上)
<script setup lang="ts">
const { likes = 0, isPublished = false } = defineProps<Props>();
</script>
响应式Props解构
const { foo } = defineProps(['foo'])
watchEffect( () => {
console.log(foo);
})
上面这段代码在3.5版本之前只会执行一次,foo被视为一个常量。3.5版本之后,编译器会自动为Props解构的内容前面添加props,等效于下面这段代码:
const props = defineProps(['foo'])
watchEffect( () => {
console.log(props.foo);
})
需要注意foo并没有被修改为响应式数据源,于是watch(foo, /* ... */)依旧是无效的,应该用getter进行包装:watch(() => foo, /* ... */)。
传递Props的细节
Prop名字格式
应该在script代码中使用camelCase命名,如greetingMessage。而在传递props时,以下两种方法的代码均能正常工作:
<MyComponent greetingMessage="hello" />
<MyComponent greeting-message="hello" />
但是更推荐第二种,因为和html的attribute对齐。
静态 vs. 动态 Props
:是v-bind的缩写,用于支持props动态绑定
<BlogPost :title="post.title" />
<BlogPost :title="post.title + ' by ' + post.author.name" />
也就是说,会将""中的内容解析为script代码。
传递不同的值类型
如果不使用v-bind,传入的值永远是字符串类型,比如下面的代码会出错:
<BlogPost title="42" />
所以即使是传入数字常量,也需要用v-bind,同样的情况对其他类型也适用:
- Boolean
- Array
- Object
使用一个对象绑定多个prop
<BlogPost :id="post.id" :title="post.title" />
利用没有参数的v-bind,可以达到与上面代码相同的效果:
<BlogPost v-bind="post" />
单向数据流
props的更新仅会从父组件传递到子组件,而不会反向传递,因此不应该在子组件中更改prop。
prop用于初始值
这种情况下应该定义一个新的变量
const props = defineProps(['initialCounter'])
const counter = ref(props.initialCounter)
需要基于prop的值进行变换
这种情况应该使用computed
const props = defineProps(['size])
const normalizedSize = computed(() => props.size.trim().toLowerCase())
数组/对象类型
由于数据/对象类型的prop传入的是引用,所以修改可以在原数据上生效,但是不应该这样做。
Prop校验
这部分列举了所有可以对prop做的校验方式
defineProps({
propA: Number,
propB: [String, Number],
propC: {
type: String,
required: true
},
propD: {
type: [String, null],
required: true
},
propE: {
type: Number,
default: 100
},
propF: {
type: Object,
default(rawProps){
return { message: 'hello' }
}
},
propG: {
validator(value, props){
return ['success', 'warning', 'danger'].includes(value)
}
},
propH: {
type: Function,
// default函数本身会作为默认值,而非字符串
default(){
return 'Default Function'
}
}
})
补充
default的实现原理
当指定传入参数的值为undefined时,即使是显性指定,也会被修改为default所指定的值。
Boolean类型
defineProps({
disabled: Boolean
})
对于Boolean类型的prop可以这样写:
<!-- 等同于:disabled="true" -->
<MyComponent disabled />
<!-- 等同于:disabled="false" -->
<MyComponent />