1.Props 声明(defineProps)
// 字符串数组
const props = defineProps(['foo'])
// 对象 key 是 prop 的名称,而值则是该 prop 预期类型的构造函数(跟ts不一样)
defineProps({ title: String, likes: Number })
//ts 泛型
defineProps<{ title?: string likes?: number }>()
ts语法限制:
//接口或对象字面类型可以包含从其他文件导入的类型引用,但是,传递给 `defineProps` 的泛型参数本身**不能**是一个导入的类型
import { Props } from './other-file'
// 目前不支持! 这是因为 Vue 组件是单独编译的,编译器目前不会抓取导入的文件以分析源类型。
defineProps<Props>()
ts Props 默认值(withDefaults)
export interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
2.Prop 校验
- 所有 prop 默认都是可选的,除非声明了
required: true,如果使用的是ts是通过?来实现参数可选eg:defineProps<{ title?: string likes?: number }>() - 除
Boolean外的未传递的可选 prop 将会有一个默认值undefined。Boolean是false,可以通过为它设置default来更改
defineProps({
// 基础类型检查
// (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
propA: Number,
// 多种可能的类型
propB: [String, Number],
// 必传,且为 String 类型
propC: { type: String, required: true },
// Number 类型的默认值
propD: { type: Number, default: 100 },
// 对象类型的默认值
propE: {
type: Object, // 对象或数组的默认值
// 必须从一个工厂函数返回。
// 该函数接收组件所接收到的原始 prop 作为参数。
default(rawProps) {
return { message: 'hello' }
}
}, // 自定义类型校验函数
propF: {
validator(value) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
}, // 函数类型的默认值
propG: {
type: Function,
// 不像对象或数组的默认,这不是一个
// 工厂函数。这会是一个用来作为默认值的函数
default() {
return 'Default function'
}
}
})
defineProps() 宏中的参数不可以访问 <script setup> 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中。
补充 使补充用一个对象绑定多个 prop
const post = { id: 1, title: 'My Journey with Vue' }
<BlogPost v-bind="post" />
3.单向数据流
所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。
更改对象 / 数组类型的 props
当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递,而对 Vue 来说,禁止这样的改动,虽然可能生效,但有很大的性能损耗,比较得不偿失。
透传Attributes
“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 [props] 或 [emits] 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。
对 class 和 style 的合并
如果一个子组件的根元素已经有了 class 或 style attribute,它会和从父组件上继承的值合并。
<MyButton class="large" />
<!-- <MyButton> 的模板 -->
<button class="btn">click me</button>
//则最后渲染出的 DOM 结果会变成
<button class="btn large">click me</button>
深层组件继承
有些情况下一个组件会在根节点上渲染另一个组件。
例如,我们重构一下 <MyButton>,让它在根节点上渲染 <BaseButton>:
此时 <MyButton> 接收的透传 attribute 会直接继续传给 <BaseButton>。
禁用 Attributes 继承(inheritAttrs: false)
如果你使用了 <script setup>,你需要一个额外的 <script> 块来书写这个选项声明:
<script>
// 使用普通的 <script> 来声明选项
export default {
inheritAttrs: false
}
</script>
<script setup>
// ...setup 部分逻辑
</script>
在模板的表达式中直接用 $attrs 访问到透传进来的 attribute
多根节点的 Attributes 继承
和单根节点组件有所不同,有着多个根节点的组件没有自动 attribute 透传行为。如果 $attrs 没有被显式绑定,将会抛出一个运行时警告。
useAttrs()
如果需要,你可以在 <script setup> 中使用 useAttrs() API 来访问一个组件的所有透传 attribute:
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>