11 Vue3中的computed计算属性

概述

Computed properties are unique data types that will reactively update only when the source data used within the property is updated. By defining a data property as a computed property, we can perform the following activities:

  • Apply custom logic on the original data property to calculate the computed property’s value
  • Track the changes of the original data property to calculate the updated value of the computed property
  • Reuse the computed property as local data anywhere within the Vue component

计算属性是一种独特的数据类型,只有在属性中使用的源数据更新时才会被动更新。通过将数据属性定义为计算属性,我们可以执行以下活动:

  • 在原始数据属性上应用自定义逻辑,计算计算属性的值

  • 跟踪原始数据属性的变化,计算计算属性的更新值

  • 在 Vue 组件中的任何位置将计算属性作为本地数据重复使用

By default, the Vue engine automatically caches the computed properties, making them more performant at updating the UI than using the property of the returned value of data, or using a Vue component’s method.

默认情况下,Vue 引擎会自动缓存计算属性,这使得它们在更新 UI 时比使用数据返回值的属性或使用 Vue 组件的方法更高效。

The syntax of a computed property is like writing a component method with a return value, nested under the computed property of the Vue component:

计算属性的语法就像编写一个带有返回值的组件方法,嵌套在 Vue 组件的计算属性下:

<script>
export default {
  computed: {
    yourComputedProperty() {
      /* need to have return value */
    }
  }
}
script>

Within the computed property’s logic, you can access any component’s data property, method, or other computed property using the this instance, which is the reference to the Vue component instance itself. An example of using the this instance is shown here:

在计算属性的逻辑中,你可以使用 this 实例访问任何组件的数据属性、方法或其他计算属性,this 实例是对 Vue 组件实例本身的引用。下面是一个使用 this 实例的示例:

<script>
export default {
  data() {
    return {
      yourData: "your data"
    }
  },
  computed: {
    yourComputedProperty() {
      return `${this.yourData}-computed`;
    }
  }
}
script>

计算属性的使用场景

Let’s look at some examples of where you should consider using a computed property.

让我们举例说明在哪些情况下应考虑使用计算属性。

表单校验

In the following example, we have an input field, which attaches to the name data property, and error is a computed property. If name contains a falsy value (which means name is an empty string, 0, undefined, null, or false), error will be assigned a value of “Name is required”. Otherwise, it will be empty.

在下面的示例中,我们有一个与 name 数据属性相连的输入字段,而 error 是一个计算属性。如果 name 包含虚假值(即 name 为空字符串、0、未定义、空或 false),error 将被赋值为 “Name is required”。否则,该值将为空。

The component then renders the value of the error property accordingly:

然后,组件会相应地渲染错误属性的值:

<template>
  <input v-model="name">
  <div>
    <span>{{ error }}span>
  div>
template>
<script>
export default {
  data() {
    return {
      name: '',
    }
  },
  computed: {
    error() {
      return this.name ? '' : 'Name is required'
    }
  }
}
script>

合并数据属性

You can use computed props to combine multiple data properties to generate a single computed property. Take the following code for instance. We combine two pieces of data – title and surname – into one computed string, formalName, and render its value using template:

你可以使用计算道具来组合多个数据属性,生成一个计算属性。以下面的代码为例。我们将标题和姓氏这两个数据合并为一个计算字符串 formalName,并使用模板呈现其值:

<template>
  <div>{{ formalName }}div>
template>
<script>
export default {
  data() {
    return {
      title: 'Mr.',
      surname: 'Smith'
    }
  },
  computed: {
    formalName() {
      return `${this.title} ${this.surname}`;
    }
  }
}
script>

计算和显示复杂信息

Sometimes there is a need to perform an extra calculation or to extract specific information from one large data object source. Computed properties help to achieve this goal while keeping our code readable.

有时需要执行额外的计算,或从一个大型数据对象源中提取特定信息。计算属性有助于实现这一目标,同时保持代码的可读性。

Take a large data object, such as post. This data object has a nested fields property, which contains several additional information objects, such as the full name of author and an array of entries objects. Each entry in entries contains further information, such as title, content, and a feature flag indicating whether the entry should be featured:

以一个大型数据对象为例,如 post。该数据对象有一个嵌套字段属性,其中包含多个附加信息对象,如作者全名和条目对象数组。条目中的每个条目都包含更多信息,如标题、内容和表示条目是否应被突出显示的特征标志:

<script>
export default {
  data() {
    return {
      post: {
        fields: {
          author: {
            firstName: 'John',
            lastName: 'Doe'
          },
          entries: [{
            title: "Entry 1",
            content: "Entry 1's content",
            featured: true
          },
            {
              title: "Entry 2",
              content: "Entry 2's content",
              featured: false
            }]
        }
      }
    }
  },
}
script>

In this scenario, you need to perform the following steps:

  • Display the full name of the post’s author.
  • Calculate and display the total number of entries included.
  • Display a list of entries that have the feature flag turned on (feature: true).

在这种情况下,您需要执行以下步骤:

  • 显示帖子作者的全名。
  • 计算并显示包含的条目总数。
  • 显示已打开特征标志(特征:true)的条目列表。

By using computed properties, we can decouple the previous post object into several computed data properties while keeping the original post object unchanged, as follows.

通过使用计算属性,我们可以将之前的文章对象解耦为多个计算数据属性,同时保持原始文章对象不变,如下所示。

<script>
export default {
  data() {
    return {
      post: {
        fields: {
          author: {
            firstName: 'John',
            lastName: 'Doe'
          },
          entries: [{
            title: "Entry 1",
            content: "Entry 1's content",
            featured: true
          },
            {
              title: "Entry 2",
              content: "Entry 2's content",
              featured: false
            }]
        }
      }
    }
  },
  computed: {
    // fullName 用于合并 post.fields.author 的名和姓:
    fullName() {
      const {firstName, lastName} =
          this.post.fields.author;
      return `${firstName} ${lastName}`
    },
    // totalEntries 包含 post.fields.entries 数组的长度:
    totalEntries () {
      return this.post.fields.entries.length
    },
    // featuredEntries 包含根据每个条目的特征属性过滤后的 post.fields.entries 列表,使用的是 filter 内置数组方法:
    featuredEntries() {
      const { entries } = this.post.fields;
      return entries.filter(entry => !!entry.featured)
    }
  }
}
script>

You then use the simplified and semantic computed properties to render the information in your component’s template.

然后,使用简化和语义计算属性在组件模板中呈现信息。

<template>
  <div>
    <p>{{ fullName }}p>
    <p>{{ totalEntries }}p>
    <p>{{ featuredEntries }}p>
  div>
template>

Computed properties are very valuable to Vue developers when creating performant components. In the next exercise, we will explore how to use them inside a Vue component.

在创建高性能组件时,计算属性对 Vue 开发人员非常有价值。在下一个练习中,我们将探讨如何在 Vue 组件中使用它们。

练习:使用计算属性

In this exercise, you will use a computed property to help cut down the amount of code you need to write inside your Vue templates by concisely outputting basic data.

在本练习中,您将使用计算属性,通过简洁地输出基本数据,帮助减少 Vue 模板中需要编写的代码量。

Let’s create a new Vue component called Exercise2-01 by adding the Exercise2-01.vue file to the ./src/components/ folder:

让我们在 ./src/components/ 文件夹中添加 Exercise2-01.vue 文件,创建一个名为 Exercise2-01 的新 Vue 组件:

在App.vue中,引入并使用该组件:

<script setup>
import Exercise from "./components/Exercise2-01.vue";
script>
<template>
  <Exercise/>
template>

Open Exercise2-01.vue and let’s create the code block structure for the Vue component, as follows:

打开 Exercise2-01.vue,为 Vue 组件创建代码块结构,如下所示:

<template>
template>
<script>
export default {
}
script>

In