Vue 3 计算属性 (Computed Properties)

计算属性是 Vue 3 中的一个非常重要的功能,它允许你根据已有的响应式数据计算出新的数据。计算属性的值会根据其依赖的数据变化而自动更新,因此可以提高性能并减少重复的代码。计算属性具有缓存功能,只有当依赖的响应式数据发生变化时,计算属性才会重新计算。

1. 计算属性的基本使用

计算属性的定义是通过 computed 选项来实现的。你可以在 computed 里定义多个计算属性,并通过访问这些计算属性来获取它们的值。

<template>
  <div>
    <p>Original Price: {{ price }}</p>
    <p>Discounted Price: {{ discountedPrice }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100
    };
  },
  computed: {
    discountedPrice() {
      return this.price * 0.9;  // 10% discount
    }
  }
};
</script>

在这个例子中,discountedPrice 是一个计算属性,它基于 price 计算出折扣后的价格。每当 price 的值发生变化时,discountedPrice 会自动重新计算。

2. 计算属性的缓存

计算属性具有缓存特性,只有在相关的响应式依赖(如 price)发生变化时,计算属性才会重新计算。如果相关的依赖没有变化,计算属性会返回之前缓存的值,从而提高性能。

例如,如果你多次访问计算属性 discountedPrice,它只会在 price 发生变化时重新计算,否则会使用缓存的结果:

<template>
  <div>
    <p>Price: {{ price }}</p>
    <p>Discounted Price: {{ discountedPrice }}</p>
    <button @click="price += 10">Increase Price</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100
    };
  },
  computed: {
    discountedPrice() {
      console.log('Calculating discounted price...');
      return this.price * 0.9;
    }
  }
};
</script>

每次点击 “Increase Price” 按钮时,price 的值会增加,而 discountedPrice 会重新计算,并输出日志。

3. 计算属性的 getter 和 setter

在 Vue 3 中,你不仅可以定义计算属性的 getter,还可以定义 setter。当你需要在计算属性被赋值时进行某些处理时,setter 会非常有用。

3.1. Getter

默认情况下,计算属性只包含 getter,它根据相关依赖的变化来重新计算值。

<template>
  <div>
    <p>Original Price: {{ price }}</p>
    <p>Discounted Price: {{ discountedPrice }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100
    };
  },
  computed: {
    discountedPrice() {
      return this.price * 0.9;
    }
  }
};
</script>

3.2. Setter

你可以为计算属性添加 setter,这样在计算属性被赋新值时,Vue 会调用这个 setter 函数。在 setter 中,你可以定义计算属性的新值应该如何反映到原始数据上。

<template>
  <div>
    <p>Original Price: {{ price }}</p>
    <p>Discounted Price: <input v-model="discountedPrice" /></p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100
    };
  },
  computed: {
    discountedPrice: {
      get() {
        return this.price * 0.9;
      },
      set(newValue) {
        this.price = newValue / 0.9;  // 假设折扣率固定为 0.9
      }
    }
  }
};
</script>

在这个例子中,discountedPrice 具有 getter 和 setter。当用户在输入框中修改 discountedPrice 时,set 方法会被调用,进而改变 price 的值。

4. 计算属性 vs 方法

计算属性和方法在很多情况下都可以完成相似的任务,但它们之间有一些重要的区别。

  • 计算属性:基于依赖的响应式数据,只有在依赖的值变化时才会重新计算。并且有缓存机制。
  • 方法:每次调用时都会重新执行函数,没有缓存。

计算属性的优势

<template>
  <div>
    <p>Discounted Price: {{ discountedPrice }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100
    };
  },
  computed: {
    discountedPrice() {
      return this.price * 0.9;
    }
  }
};
</script>

每次访问 discountedPrice 时,计算属性会根据 price 的变化自动更新,并且只有在 price 改变时才会重新计算。

方法的实现

<template>
  <div>
    <p>Discounted Price: {{ getDiscountedPrice() }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100
    };
  },
  methods: {
    getDiscountedPrice() {
      return this.price * 0.9;
    }
  }
};
</script>

在这个例子中,每次访问 getDiscountedPrice() 时,都会重新计算折扣后的价格,哪怕 price 没有变化。

5. 计算属性的复杂场景

你可以使用计算属性处理复杂的逻辑,例如格式化数据或根据多个数据源组合信息:

<template>
  <div>
    <p>Full Name: {{ fullName }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    };
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    }
  }
};
</script>

在这个例子中,fullName 是一个计算属性,它将 firstNamelastName 拼接成一个完整的名字。

6. 计算属性的性能优化

由于计算属性具有缓存机制,它们比方法更适合用于依赖变化的计算。计算属性只会在相关数据变化时重新计算,这样可以避免不必要的计算和性能开销。

总结

  • 计算属性 是基于已有的数据计算新的值,并且只有当相关数据变化时才会重新计算。
  • getter 用于获取计算属性的值,而 setter 用于修改计算属性的值。
  • 计算属性与 方法 类似,但计算属性有缓存机制,能够提高性能。
  • 计算属性非常适合用于处理复杂的计算逻辑,如数据格式化、动态组合等。

计算属性是 Vue 3 中强大而高效的功能之一,能够使得你的组件更加简洁并优化性能。