Vue props

props是Vue中的一个配置选项。

使用 props,我们可以通过组件标签的自定义属性将数据传递给组件。

将数据传递给组件

您还记得上一页中所有三个组件都表示“Apple”的示例吗?通过 props,我们现在可以将数据传递给我们的组件,为它们提供不同的内容并使它们看起来不同。

让我们制作一个简单的页面来显示“Apples”、“Pizza”和“Rice”。

在主应用程序文件中App.vue我们创建自己的属性“food-name”来传递一个带有<food-item/>组件标签:

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>

在组件内部接收数据

接收通过 'food-item' 属性发送的数据App.vue我们使用这个新的“props”配置选项。我们列出收到的属性,以便我们的组件 *.vue 文件了解它们,现在我们可以在任何我们想要的地方使用这些 props,就像使用数据属性一样。

FoodItem.vue:

<script>
  export default {
    props: [
      'foodName'
    ]
  }
</script>

Props 属性用破折号书写-分隔单词(kebab-case)<template>标签,但 kebab-case 在 JavaScript 中是不合法的。因此,我们需要在 JavaScript 中将属性名称编写为驼峰命名法,Vue 会自动理解这一点!

最后,我们的例子<div>“Apples”、“Pizza”和“Rice”的元素如下所示:

示例

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 来实现不同的功能,并且我们可以定义在创建组件时如何给出属性的规则App.vue

让我们添加一个新的属性“isFavorite”。这应该是一个具有值的布尔值true或者false这样我们就可以直接使用它v-show显示最喜欢的邮票<img>标记该食物是否被认为是最喜欢的。

要传递数据类型与 String 不同的 props,我们必须编写v-bind:在我们要传递的属性前面。

这就是我们传递布尔值 'isFavorite' 属性的方式App.vue作为属性“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>

我们在里面收到布尔值 'isFavorite' 属性FoodItem.vue如果该食物被认为是最喜欢的,则显示最喜欢的标记:

示例

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>
运行示例 »

图片:要使上面示例中的图片在您计算机上的项目中本地工作,请打开上面的示例,右键单击该图片,选择 "Save Image As..." 并将其保存在项目中的 "public" 文件夹中。


道具界面

上面的例子中,根据里面的代码FoodItem.vue,我们无法确定是否收到了 'isFavorite' 属性,也无法确定它是否是布尔值。为了帮助我们实现这一点,我们可以定义我们收到的 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,您会在控制台中收到警告,如下所示:

Screenshot of wrong data type prop warning

此类警告有助于让我们自己和其他人知道某个组件未按其应有的方式使用,并告诉我们出了什么问题,以便我们可以纠正错误。


所需道具

为了告诉 Vue 需要一个 prop,我们需要将 prop 定义为一个对象。让我们将“foodName”属性设为必需,如下所示:

FoodItem.vue:

<script>
  export default {
    // props: ['foodName','foodDesc','isFavorite']
    props: {
      foodName: {
        type: String,
        required: true
      },
      foodDesc: String,
      isFavorite: Boolean
    }
  }
</script>

如果组件是从父元素创建的(在我们的例子中App.vue)并且未定义必需的 prop,您会在控制台中收到警告,如下所示:

Screenshot of required prop warning

此类警告有助于让我们自己和其他人知道某个组件未按其应有的方式使用,并告诉我们出了什么问题,以便我们可以纠正错误。


默认值

我们可以为 prop 设置默认值。

让我们为 'FoodItem' 组件中的 'foodDesc' 属性创建一个默认值,然后在不定义 'foodDesc' 属性的情况下为大米创建这样一个项目:

示例

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>
运行示例 »

道具验证器功能

我们还可以定义一个验证器函数来决定 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 个字符。


修改道具

当在父元素中创建组件时,我们不允许更改子元素中接收到的 prop 的值。所以里面FoodItem.vue我们无法更改从中获得的 'isFavorite' 属性的值App.vue。该 prop 对于父级是只读的,即App.vue在我们的例子中。

但假设我们希望用户能够通过单击按钮来更改最喜欢的食物。现在需要更改 'isFavorite' 属性,但我们不能这样做,因为它是只读的。

我们不允许更改“isFavorite”。这会产生错误。

methods: {
  toggleFavorite() { 
    this.isFavorite = !this.isFavorite;
  }
}

为了解决这个问题,我们可以使用 prop 来初始化一个新的数据值“foodIsFavorite”,在里面FoodItem.vue, 像这样:

data() {
  return { 
    foodIsFavorite: this.isFavorite
  }
}

现在我们可以添加一个方法,以便用户可以切换这个新数据值:

methods: {
  toggleFavorite() { 
    this.foodIsFavorite = !this.foodIsFavorite;
  }
}

我们还必须为每个食物添加切换按钮,并更改v-show在里面<img>标签依赖于新的数据属性“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>
运行示例 »

Vue练习

通过练习测试一下

练习:

我们必须在组件中编写什么,才能接收通过 App.vue 的“fish-name”属性作为 prop 发送的数据?

<script>
  export default {
    : [
      ''
    ]
  }
</script>

开始练习