Close
升级到 Vue 3 | Vue 2 EOL

Props

本页假设您已经阅读了 组件基础。如果您是组件新手,请先阅读它。

Prop 命名规范 (camelCase vs kebab-case)

HTML 属性名称不区分大小写,因此浏览器会将任何大写字符解释为小写。这意味着当您使用 DOM 内模板时,camelCased prop 名称需要使用其 kebab-cased(连字符分隔)等效项

Vue.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>

同样,如果您使用字符串模板,则此限制不适用。

Prop 类型

到目前为止,我们只看到 props 被列为字符串数组

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

通常,您希望每个 prop 都是特定类型的值。在这种情况下,您可以将 props 列为一个对象,其中属性的名称和值分别包含 prop 名称和类型

props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}

这不仅记录了您的组件,而且还会在浏览器 JavaScript 控制台中警告用户,如果他们传递了错误的类型。您将在本页面的后面学习更多关于 类型检查和其他 prop 验证 的内容。

传递静态或动态 Props

到目前为止,您已经看到 props 传递了一个静态值,例如在

<blog-post title="My journey with Vue"></blog-post>

您还看到 props 使用 v-bind 动态分配,例如在

<!-- Dynamically assign the value of a variable -->
<blog-post v-bind:title="post.title"></blog-post>

<!-- Dynamically assign the value of a complex expression -->
<blog-post
v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>

在上面的两个示例中,我们碰巧传递了字符串值,但实际上任何类型的值都可以传递给 prop。

传递数字

<!-- Even though `42` is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string. -->
<blog-post v-bind:likes="42"></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:likes="post.likes"></blog-post>

传递布尔值

<!-- Including the prop with no value will imply `true`. -->
<blog-post is-published></blog-post>

<!-- Even though `false` is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string. -->
<blog-post v-bind:is-published="false"></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

传递数组

<!-- Even though the array is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string. -->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>

传递对象

<!-- Even though the object is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string. -->
<blog-post
v-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:author="post.author"></blog-post>

传递对象的属性

如果您想将对象的全部属性作为 props 传递,可以使用不带参数的 v-bindv-bind 而不是 v-bind:prop-name)。例如,给定一个 post 对象

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

以下模板

<blog-post v-bind="post"></blog-post>

将等效于

<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>

单向数据流

所有 props 在子属性和父属性之间形成单向向下绑定:当父属性更新时,它将向下流向子属性,但反之则不行。这可以防止子组件意外地改变父组件的状态,这会使您的应用程序的数据流更难理解。

此外,每次父组件更新时,子组件中的所有 props 都会使用最新值刷新。这意味着您不应该尝试在子组件中改变 prop。如果您这样做,Vue 会在控制台中警告您。

通常有两种情况,您可能会想要改变 prop

  1. prop 用于传递初始值;子组件希望随后将其用作本地数据属性。在这种情况下,最好定义一个本地数据属性,使用 prop 作为其初始值

    props: ['initialCounter'],
    data: function () {
    return {
    counter: this.initialCounter
    }
    }
  2. prop 作为原始值传递,需要进行转换。在这种情况下,最好使用 prop 的值定义一个计算属性

    props: ['size'],
    computed: {
    normalizedSize: function () {
    return this.size.trim().toLowerCase()
    }
    }

请注意,JavaScript 中的对象和数组是通过引用传递的,因此如果 prop 是数组或对象,在子组件中改变对象或数组本身影响父组件状态。

Prop 验证

组件可以为其 props 指定要求,例如您已经看到的类型。如果要求没有满足,Vue 会在浏览器的 JavaScript 控制台中警告您。这在开发旨在供他人使用的组件时特别有用。

要指定 prop 验证,您可以向 props 的值提供一个包含验证要求的对象,而不是字符串数组。例如

Vue.component('my-component', {
props: {
// Basic type check (`null` and `undefined` values will pass any type validation)
propA: Number,
// Multiple possible types
propB: [String, Number],
// Required string
propC: {
type: String,
required: true
},
// Number with a default value
propD: {
type: Number,
default: 100
},
// Object with a default value
propE: {
type: Object,
// Object or array defaults must be returned from
// a factory function
default: function () {
return { message: 'hello' }
}
},
// Custom validator function
propF: {
validator: function (value) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
}
}
})

当 prop 验证失败时,Vue 会生成一个控制台警告(如果使用开发版本)。

请注意,props 在组件实例创建之前进行验证,因此实例属性(例如 datacomputed 等)在 defaultvalidator 函数中不可用。

类型检查

type 可以是以下原生构造函数之一

此外,type 也可以是自定义构造函数,断言将使用 instanceof 检查进行。例如,假设存在以下构造函数

function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}

您可以使用

Vue.component('blog-post', {
props: {
author: Person
}
})

来验证 author prop 的值是否使用 new Person 创建。

非 Prop 属性

非 Prop 属性是传递给组件但没有对应定义的 prop 的属性。

虽然明确定义的 props 是传递信息给子组件的首选方式,但组件库的作者无法总是预见其组件可能使用的上下文。这就是为什么组件可以接受任意属性,这些属性将添加到组件的根元素。

例如,假设我们正在使用一个第三方 bootstrap-date-input 组件,该组件使用一个 Bootstrap 插件,该插件要求 input 上有一个 data-date-picker 属性。我们可以将此属性添加到我们的组件实例

<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>

并且 data-date-picker="activated" 属性将自动添加到 bootstrap-date-input 的根元素。

替换/合并现有属性

想象一下,这是 bootstrap-date-input 的模板

<input type="date" class="form-control">

为了指定日期选择器插件的主题,我们可能需要添加一个特定的类,例如

<bootstrap-date-input
data-date-picker="activated"
class="date-picker-theme-dark"
></bootstrap-date-input>

在这种情况下,class 定义了两个不同的值

对于大多数属性,传递给组件的值将替换组件设置的值。例如,传递 type="text" 将替换 type="date",并且可能会导致其失效!幸运的是,classstyle 属性更智能一些,因此这两个值将被合并,最终值为:form-control date-picker-theme-dark

禁用属性继承

如果您 **不** 希望组件的根元素继承属性,可以在组件的选项中设置 inheritAttrs: false。例如

Vue.component('my-component', {
inheritAttrs: false,
// ...
})

这在与 $attrs 实例属性结合使用时特别有用,该属性包含传递给组件的属性名称和值,例如

{
required: true,
placeholder: 'Enter your username'
}

使用 inheritAttrs: false$attrs,您可以手动决定要将属性转发到哪个元素,这对于 基础组件 来说通常是可取的

Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})

请注意,inheritAttrs: false 选项 **不会** 影响 styleclass 绑定。

这种模式允许您将基础组件更像原始 HTML 元素一样使用,而不必关心其根元素实际上是什么

<base-input
label="Username:"
v-model="username"
required
placeholder="Enter your username"
></base-input>