Vue2 计算属性(computed)入门与实战指南

1,079 阅读3分钟

Vue2 计算属性(computed)入门与实战指南

一、初识 computed

1. 为什么需要 computed?

在 Vue 开发中,经常需要根据多个响应式数据计算出一个新的值。如果直接在模板中进行复杂计算(如 {{ price * quantity }}),不仅难以维护,还会重复计算导致性能问题。computed 应运而生,它通过以下特性解决这些问题:

  • 缓存机制:只有依赖的数据发生变化时才会重新计算
  • 声明式语法:将计算逻辑集中在 computed 属性中
  • 自动依赖追踪:无需手动管理依赖关系

2. 基础语法

new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性本质上是一个惰性求值的函数
    reversedMessage() {
      return this.message.split('').reverse().join('');
    }
  }
});

二、核心特性解析

1. 与 methods 的本质区别

特性computedmethods
执行时机首次访问时缓存结果每次调用都执行
性能消耗依赖变化才重新计算总是重新执行
使用场景需要频繁访问的计算值一次性操作

示例对比:

<!-- computed 版本 -->
<p>{{ reversedMessage }}</p >
<p>{{ reversedMessage }}</p >

<!-- methods 版本 -->
<p>{{ reversedMessage() }}</p >
<p>{{ reversedMessage() }}</p >

2. 缓存机制验证

new Vue({
  el: '#app',
  data: {
    count: 0
  },
  computed: {
    doubleCount() {
      console.log('computed 执行');
      return this.count * 2;
    }
  }
});

在模板中多次使用 {{ doubleCount }},控制台只会输出一次 "computed 执行",证明缓存生效。

三、最佳实践示例:购物车总价计算

1. 场景描述

购物车中包含多个商品,每个商品有单价和数量,需要实时计算总价。当用户修改某个商品的数量或价格时,总价应自动更新。

2. 实现代码

<div id="app">
  <div v-for="item in cartItems" :key="item.id">
    <input type="number" v-model.number="item.price" placeholder="单价">
    <input type="number" v-model.number="item.quantity" placeholder="数量">
  </div>
  <p>总价:{{ totalPrice }}</p >
</div>
new Vue({
  el: '#app',
  data: {
    cartItems: [
      { id: 1, price: 100, quantity: 2 },
      { id: 2, price: 200, quantity: 1 }
    ]
  },
  computed: {
    totalPrice() {
      return this.cartItems.reduce((sum, item) => {
        return sum + item.price * item.quantity;
      }, 0);
    }
  }
});

3. 优化亮点

  • 自动响应变化:修改任意商品的 price/quantity 时自动重新计算
  • 性能优化:相比直接在模板中写 {{ cartItems.reduce(...) }},computed 避免每次渲染都执行计算
  • 代码复用:多个位置需要总价时只需引用同一个 computed 属性

四、进阶使用技巧

1. Getter 和 Setter 的应用

当需要通过 computed 属性修改数据时,可以使用带 setter 的计算属性:

computed: {
  fullName: {
    // getter 方法
    get() {
      return this.firstName + ' ' + this.lastName;
    },
    // setter 方法
    set(newValue) {
      const names = newValue.split(' ');
      this.firstName = names[0];
      this.lastName = names[1];
    }
  }
}

在模板中使用 <input v-model="fullName"> 即可同时修改 firstName 和 lastName。

2. 计算属性的依赖管理

computed: {
  discountPrice() {
    // 同时依赖 basePrice 和 discountRate
    return this.basePrice * (1 - this.discountRate);
  }
}

当 basePrice 或 discountRate 任一变化时,discountPrice 会自动重新计算。

五、常见误区与避坑指南

1. 避免在 computed 中修改数据

// 错误示范
computed: {
  count() {
    this.count++; // 修改了自身依赖的数据
    return this.count;
  }
}

这会导致无限循环更新,应改用 methodswatch

2. 注意计算属性的命名冲突

避免在 data 和 computed 中使用相同名称的属性,例如:

data() {
  return { totalPrice: 0 }
},
computed: {
  totalPrice() { /* ... */ } // 会覆盖 data 中的 totalPrice
}

六、总结与建议

何时使用 computed?

  • 需要基于多个响应式数据计算值时
  • 计算结果会被多次使用时
  • 需要性能优化的复杂计算场景

记忆口诀

"单一数据源,计算不重复,依赖自追踪,性能自然优"

通过本文的购物车示例可以看到,computed 不仅能让代码更简洁,还能显著提升性能。建议在实际开发中:

  1. 优先使用 computed 处理需要频繁访问的计算值
  2. 保持 computed 函数纯粹(无副作用)
  3. 复杂逻辑可拆分为多个 computed 属性组合使用