Vue学习笔记-Props&Attributes

147 阅读2分钟

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 事件监听器。最常见的例子就是 classstyle 和 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>