Skip to content

3.2 Props

3.2.1 Props声明

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

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

使用对象的形式

js
// 使用 <script setup>
defineProps({
  title: String,
  likes: Number
})

搭配TypeScript

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

3.2.2 传递prop的细节

Prop名字格式

js
defineProps({
  greetingMessage: String
})
html
<span>{{ greetingMessage }}</span>
html
<MyComponent greeting-message="hello" />

传递不同的值类型

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

<!-- 根据一个变量的值动态传入 -->
<BlogPost :likes="post.likes" />
  • Boolean
html
<!-- 仅写上 prop 但不传值,会隐式转换为 `true` -->
<BlogPost is-published />

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

<!-- 根据一个变量的值动态传入 -->
<BlogPost :is-published="post.isPublished" />
  • Array
html
<!-- 虽然这个数组是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :comment-ids="[234, 266, 273]" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :comment-ids="post.commentIds" />
  • Object
html
<!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
 />

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

使用一个对象绑定多个 prop

js
const post = {
  id: 1,
  title: 'My Journey with Vue'
}
html
<BlogPost v-bind="post" />
<!-- 等价于 -->
 <BlogPost :id="post.id" :title="post.title" />

3.2.3 单向数据流

不应该在子组件中去更改一个 prop

prop 被用于传入初始值,新定义一个局部数据属性,从 props 上获取初始值

js
const props = defineProps(['initialCounter'])

// 计数器只是将 props.initialCounter 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.initialCounter)

需要对传入的 prop 值做进一步的转换,基于该 prop 值定义一个计算属性

js
const props = defineProps(['size'])

// 该 prop 变更时计算属性也会自动更新
const normalizedSize = computed(() => props.size.trim().toLowerCase())

更改对象 / 数组类型的 props

应该尽可能避免这样的更改

3.2.4 Prop校验

js
defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true
  },
  // 必传但可为 null 的字符串
  propD: {
    type: [String, null],
    required: true
  },
  // Number 类型的默认值
  propE: {
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propF: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  },
  // 自定义类型校验函数
  // 在 3.4+ 中完整的 props 作为第二个参数传入
  propG: {
    validator(value, props) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propH: {
    type: Function,
    // 不像对象或数组的默认,这不是一个
    // 工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})

运行时类型检查

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
  • Error
js
// 如果该类型是必传但可为 null 的
defineProps({
  id: {
    type: [String, null],
    required: true
  }
})

3.2.5 Boolean类型转换

html
<!-- 等同于传入 :disabled="true" -->
<MyComponent disabled />

<!-- 等同于传入 :disabled="false" -->
<MyComponent />
js
// disabled 将被转换为 true
defineProps({
  disabled: [Boolean, Number]
})

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

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

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