引言
组件在被创建时所需要从外部获取的初始状态值,可以通过Vue Props来声明。显示声明所需要,同时"放过"透传的 attribute(见后一篇)

一,声明Props

1. 简单数组声明

1)SFC中的 <script setup>内,利用defineProps()宏来声明

<script setup>
const props = defineProps(['foo'])

console.log(props.foo)
</script>

2)export + setup()内通过props选项声明

export default {
  props: ['foo'],
  setup(props) {
    // setup() 接收 props 作为第一个参数
    console.log(props.foo)
  }
}

2. 详细对象声明

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' }
    }
  },
  // 自定义类型校验函数
  // 在 3.4+ 中完整的 props 作为第二个参数传入
  propF: {
    validator(value, props) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个
    // 工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})

3. 若使用TypeScript特性,可用 类型标注 类声明

<script setup lang="ts">
defineProps<{
  title?: string
  likes?: number
}>()
</script>

二、传递Props

1. 名称格式的理论是实践

1)使用camelCase 格式声明

defineProps({
  greetingMessage: String
})

2)使用kebab-case格式传递值(同时支持DOM内模板)

<MyComponent greeting-message="hello" />

3)组件名推荐使用 PascalCase,因为这提高了模板的可读性,能帮助我们区分 Vue 组件和原生 HTML 元素。

2. 静态OR动态传值

1).静态传值

<BlogPost title="My journey with Vue" />

2).动态绑定传值

// String类型值
<!-- 根据一个变量的值动态传入 -->
<BlogPost :title="post.title" />

<!-- 根据一个更复杂表达式的值动态传入 -->
<BlogPost :title="post.title + ' by ' + post.author.name" />

// Number类型值
<!-- 虽然 `42` 是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :likes="42" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :likes="post.likes" />

// Boolean
<!-- 仅写上 prop 但不传值,会隐式转换为 `true` -->
<BlogPost is-published />

<!-- 虽然 `false` 是静态的值,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :is-published="false" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :is-published="post.isPublished" />

// Array
<!-- 虽然这个数组是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :comment-ids="[234, 266, 273]" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :comment-ids="post.commentIds" />

// Object
<!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
 />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :author="post.author" />

3. 声明多个Prop,由一个Object传给全部值

const post = {
  id: 1,
  title: 'My Journey with Vue'
}

<BlogPost v-bind="post" />
等价于
<BlogPost :id="post.id" :title="post.title" />

三、传值运行时行为

1. 运行时校验类型

String
Number
Boolean
Array
Object
Date
Function
Symbol
自定义类或构造函数

自定义类

// 类定义
class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}
// 声明中使用自定义类
defineProps({
  author: Person
})

2. 其他细节

1), prop默认可选, 除非指定必须required: true
2), 除 Boolean 外的未传递的可选 prop 将会有一个默认值 undefined
3), Boolean 类型的未传递 prop 将被转换为 false, 也可以通过设置default = undefined来和非Boolean类型prop的行为保持一致
4), 在 prop 的值被解析为 undefined 时,查看是否定义有default
5), 当 prop 的校验失败后,Vue 会抛出一个控制台警告 (在开发模式下)
6), 当Boolean类型prop允许多类型时, 有一种情况例外

// 传 disabled 将被解析为空字符串 (disabled="")
defineProps({
  disabled: [String, Boolean]
})

一致行为的解析

// 传 disabled 将被转换为 true
defineProps({
  disabled: [Boolean, Number]
})
  
// 传 disabled 将被转换为 true
defineProps({
  disabled: [Boolean, String]
})
  
// 传 disabled 将被转换为 true
defineProps({
  disabled: [Number, Boolean]
})