Vue 属性
Props 是 Vue 中的一个配置选项。
使用 props,我们可以通过组件标签的自定义属性将数据传递给组件。
将数据传递给组件
还记得上一页的例子吗?所有三个组件都显示了“Apple”?现在使用 props,我们可以将数据传递给组件,让它们拥有不同的内容,并呈现不同的外观。
让我们创建一个简单的页面来显示“苹果”、“披萨”和“米饭”。
在主应用程序文件 App.vue
中,我们创建了自己的属性“food-name”来传递一个带有 <food-item/>
组件标签的 prop。
App.vue
:
<template>
<h1>Food</h1>
<food-item food-name="Apples"/>
<food-item food-name="Pizza"/>
<food-item food-name="Rice"/>
</template>
<script></script>
<style>
#app > div {
border: dashed black 1px;
display: inline-block;
width: 120px;
margin: 10px;
padding: 10px;
background-color: lightgreen;
}
</style>
接收组件内的 data
要接收从 App.vue
发送的通过“food-item”属性发送的数据,我们使用这个新的“props”配置选项。我们列出接收到的属性,以便我们的组件 *.vue 文件了解它们,现在我们可以在任何地方使用 props,就像使用 data 属性一样。
FoodItem.vue
:
<script>
export default {
props: [
'foodName'
]
}
</script>
Props 属性在 <template>
标签中使用连字符 -
来分隔单词(短横线命名法),但短横线命名法在 JavaScript 中是非法的。因此,我们需要在 JavaScript 中使用驼峰命名法来编写属性名称,Vue 会自动理解!
最后,我们使用 <div>
元素创建的“苹果”、“披萨”和“米饭”示例如下:
示例
App.vue
:
<template>
<h1>Food</h1>
<food-item food-name="Apples"/>
<food-item food-name="Pizza"/>
<food-item food-name="Rice"/>
</template>
FoodItem.vue
:
<template>
<div>
<h2>{{ foodName }}</h2>
</div>
</template>
<script>
export default {
props: [
'foodName'
]
}
</script>
<style></style>
运行示例 »
很快我们就会看到如何将不同数据类型作为 props 属性传递给组件,但在那之前,让我们用每个食物类型的描述扩展代码,并将食物 <div>
元素放在一个 Flexbox 包裹器中。
示例
App.vue
:
<template>
<h1>Food</h1>
<div id="wrapper">
<food-item
food-name="Apples"
food-desc="Apples are a type of fruit that grow on trees."/>
<food-item
food-name="Pizza"
food-desc="Pizza has a bread base with tomato sauce, cheese, and toppings on top."/>
<food-item
food-name="Rice"
food-desc="Rice is a type of grain that people like to eat."/>
</div>
</template>
<script></script>
<style>
#wrapper {
display: flex;
flex-wrap: wrap;
}
#wrapper > div {
border: dashed black 1px;
margin: 10px;
padding: 10px;
background-color: lightgreen;
}
</style>
FoodItem.vue
:
<template>
<div>
<h2>{{ foodName }}</h2>
<p>{{ foodDesc }}</p>
</div>
</template>
<script>
export default {
props: [
'foodName',
'foodDesc'
]
}
</script>
<style></style>
运行示例 »
布尔型 Props
我们可以通过传递不同数据类型的 props 来实现不同的功能,我们还可以定义创建组件时从 App.vue
传递属性的规则。
让我们添加一个新的 prop 'isFavorite'。这应该是一个布尔型 prop,其值可以是 true
或 false
,这样我们就可以直接与 v-show
一起使用它,如果食物被认为是收藏,则显示一个收藏戳 <img>
标签。
要传递与 String 不同的数据类型的 props,我们必须在要传递的属性前面写 v-bind:
。
这是我们从 App.vue
将布尔值 'isFavorite' prop 作为属性 'is-favorite' 传递的方式。
App.vue
:
<template>
<h1>Food</h1>
<p>My favorite food has a diploma image attached to it.</p>
<div id="wrapper">
<food-item
food-name="Apples"
food-desc="Apples are a type of fruit that grow on trees."
v-bind:is-favorite="true"/>
<food-item
food-name="Pizza"
food-desc="Pizza has a bread base with tomato sauce, cheese, and toppings on top."
v-bind:is-favorite="false"/>
<food-item
food-name="Rice"
food-desc="Rice is a type of grain that people like to eat."
v-bind:is-favorite="false"/>
</div>
</template>
我们接收 FoodItem.vue
中的布尔值 'isFavorite' prop,如果食物被认为是收藏,则显示一个收藏戳。
示例
FoodItem.vue
:
<template>
<div>
<h2>
{{ foodName }}
<img src="/img_quality.svg" v-show="isFavorite">
</h2>
<p>{{ foodDesc }}</p>
</div>
</template>
<script>
export default {
props: ['foodName','foodDesc','isFavorite']
}
</script>
<style>
img {
height: 1.5em;
float: right;
}
</style>
运行示例 »
图像:为了使上面的示例中的图像在您机器上的项目中本地工作,请打开上面的示例,右键单击图像,选择“将图像另存为...”,然后将它保存在您项目中的“public”文件夹中。
Props 接口
在上面的示例中,根据 FoodItem.vue
中的代码,我们无法确定我们是否接收到了 'isFavorite' prop,也无法确定它是否是一个布尔值。为了帮助我们解决这个问题,我们可以定义接收到的 props 的数据类型,可以设置 props 为必填,甚至可以创建验证函数来验证接收到的 props。
定义接收到的 props 作为团队合作中其他人的文档,如果定义的规则被打破,它会在控制台中提供警告。
Props 作为对象
在 FoodItem.vue
中,我们将如何以数组形式定义 props 注释掉,将其作为参考,而是以对象形式定义 props。除了 prop 名称之外,我们还可以定义每个 prop 的数据类型,如下所示
FoodItem.vue
:
<script>
export default {
// props: ['foodName','foodDesc','isFavorite']
props: {
foodName: String,
foodDesc: String,
isFavorite: Boolean
}
}
</script>
通过这种方式定义 props,其他人可以查看 FoodItem.vue
内部,轻松地了解组件期望的内容。
如果从父元素(在本例中为 App.vue
)创建组件,并使用错误的数据类型传递 prop,您将在控制台中收到警告,如下所示
这样的警告很有用,可以让我们和其他知道组件的使用方式是否正确,并告诉我们哪里错了,以便我们可以纠正错误。
必填 Props
要告诉 Vue 一个 prop 是必填的,我们需要将该 prop 定义为对象。让我们将 'foodName' prop 设置为必填,如下所示
FoodItem.vue
:
<script>
export default {
// props: ['foodName','foodDesc','isFavorite']
props: {
foodName: {
type: String,
required: true
},
foodDesc: String,
isFavorite: Boolean
}
}
</script>
如果从父元素(在本例中为 App.vue
)创建组件,并且未定义必填 prop,您将在控制台中收到警告,如下所示
这样的警告很有用,可以让我们和其他知道组件的使用方式是否正确,并告诉我们哪里错了,以便我们可以纠正错误。
默认值
我们可以为 prop 设置默认值。
让我们为 'FoodItem' 组件中的 'foodDesc' prop 创建一个默认值,然后在不定义 'foodDesc' prop 的情况下创建米饭这样的项目
示例
App.vue
:
<template>
<h1>Food</h1>
<p>My favorite food has a diploma image attached to it.</p>
<div id="wrapper">
<food-item
food-name="Apples"
food-desc="Apples are a type of fruit that grow on trees."
v-bind:is-favorite="true"/>
<food-item
food-name="Pizza"
food-desc="Pizza has a bread base with tomato sauce, cheese, and toppings on top."
v-bind:is-favorite="false"/>
<food-item
food-name="Rice"
food-desc="Rice is a type of grain that people like to eat."
v-bind:is-favorite="false"/>
</div>
</template>
FoodItem.vue
:
<script>
export default {
props: {
foodName: {
type: String,
required: true
},
foodDesc: {
type: String,
required: false,
default: 'This is the default description.'
}
isFavorite: {
type: Boolean,
required: false,
default: false
}
}
}
</script>
运行示例 »
Props 验证函数
我们还可以定义一个验证函数,它决定 prop 值是否有效。
这些验证函数必须返回 true 或 false。当验证器返回 false 时,表示 prop 值无效。当我们在开发模式下运行页面时,无效的 prop 值会在浏览器控制台中生成警告,该警告是一个有用的提示,可以确保组件按预期使用。
假设我们希望食物描述的长度在 20 到 50 个字符之间。我们可以添加一个验证函数来确保提供的食物描述具有有效的长度。
FoodItem.vue
:
<script>
export default {
props: {
foodName: {
type: String,
required: true
},
foodDesc: {
type: String,
required: false,
default: 'This is the default description.',
validator: function(value) {
if( 20<value.length && value.length<50 ) {
return true;
}
else {
return false;
}
}
}
isFavorite: {
type: Boolean,
required: false,
default: false
}
}
}
</script>
注意:如果您将上面的验证器代码添加到本地项目中,您将在开发模式下收到警告,因为披萨的食物描述为 65 个字符,比验证器函数允许的长度长 15 个字符。
修改 Props
当在父元素中创建组件时,我们不允许更改在子元素中接收到的 prop 的值。因此,在 FoodItem.vue
中,我们不能更改从 App.vue
获取的 'isFavorite' prop 的值。该 prop 从父级读取,在本例中为 App.vue
。
但假设我们希望用户能够通过单击按钮来更改被认为是收藏的食物。现在需要更改 'isFavorite' prop,但我们不能这样做,因为它只读。
我们不允许更改 'isFavorite'。这会产生错误。
methods: {
toggleFavorite() {
this.isFavorite = !this.isFavorite;
}
}
为了解决这个问题,我们可以使用 prop 在 FoodItem.vue
中初始化一个新的数据值 'foodIsFavorite',如下所示
data() {
return {
foodIsFavorite: this.isFavorite
}
}
现在,我们可以添加一个方法,以便用户可以切换这个新的数据值
methods: {
toggleFavorite() {
this.foodIsFavorite = !this.foodIsFavorite;
}
}
我们还必须在每个食物项中添加切换按钮,并将 <img>
标签中的 v-show
更改为依赖于新的数据属性 'foodIsFavorite'。为了使我们的示例更简单,我们还将 props 声明简化为一个数组。
示例
FoodItem.vue
:
<template>
<div>
<h2>
{{ foodName }}
<img src="/img_quality.svg" v-show="foodIsFavorite">
</h2>
<p>{{ foodDesc }}</p>
<button v-on:click="toggleFavorite">Favorite</button>
</div>
</template>
<script>
export default {
props: ['foodName','foodDesc','isFavorite'],
data() {
return {
foodIsFavorite: this.isFavorite
}
},
methods: {
toggleFavorite() {
this.foodIsFavorite = !this.foodIsFavorite;
}
}
}
</script>
<style>
img {
height: 1.5em;
float: right;
}
</style>
运行示例 »