Code前端首页关于Code前端联系我们

Vue3里computed咋用?常见疑问+实战技巧一次讲透

terry 2小时前 阅读数 17 #SEO
文章标签 Vue3 computed

很多刚学Vue3的同学,对computed(计算属性)既好奇又有点懵:它和methods有啥区别?缓存啥时候生效?能不能做异步操作?今天用问答形式把这些痛点一次讲明白,还带实战例子,看完就会用~

Vue3的computed是干啥的?

简单说,computed是基于响应式数据生成新值的“自动计算器”,比如你有一个响应式变量count,想生成它的平方值,用computed就不用每次手动计算。

举个栗子:

import { ref, computed } from 'vue'  
const count = ref(2)  
const squared = computed(() => count.value * count.value)  
console.log(squared.value) // 输出4  
count.value = 3  
console.log(squared.value) // 自动变成9  

这里count是响应式数据(用ref包裹),squared会“盯住”count的变化 —— 只要count变了,squared就自动重新计算,而且计算结果会被缓存,如果count没变化,多次访问squared.value不会重复计算,直接拿缓存结果,省性能~

computed和methods有啥区别?选哪个?

最核心的区别是“缓存机制”和“调用时机”

  • methods:每次调用函数都会重新执行逻辑,比如写个getSquared()方法,不管count变没变,每次调用getSquared()都会重新算一遍。
  • computed:只有依赖的响应式数据变化时,才会重新计算;如果依赖没变化,直接复用之前的结果(缓存)。

举个场景对比:
做一个“购物车商品总价”功能,总价依赖每个商品的pricequantity,如果用methods,每次渲染页面或用户操作时,哪怕商品数据没变化,都会重新遍历所有商品计算总价;用computed的话,只有当某个商品的pricequantity变了,才会重新计算总价,性能更好。

总结选择逻辑:

  • 复杂逻辑需要“自动追踪依赖、缓存结果”时,用computed(比如数据过滤、多变量计算)。
  • 事件处理、一次性逻辑(比如点击按钮执行动作),用methods

computed的缓存啥时候生效?为啥有时不生效?

缓存生效的关键是“依赖的响应式数据是否变化”

缓存生效的情况:

只有当computed依赖的响应式数据(比如refreactive包裹的变量)发生改变时,computed才会重新计算,比如前面的countref包裹的,它变了,squared才会重新算。

缓存不生效的常见坑:

  • 依赖非响应式数据:如果computed里用了普通变量(没被ref/reactive包裹),Vue没法追踪变化,自然不会重新计算。
    反例:
    let normalNum = 2 // 普通变量,非响应式  
    const wrongComputed = computed(() => normalNum * normalNum)  
    normalNum = 3 // 这里修改普通变量,computed不会更新!  
    console.log(wrongComputed.value) // 还是4  
  • 手动修改computed本身(没写setter)computed默认是“只读”的(只有getter),如果直接赋值xxx.value = 新值,会报错,这种情况下“修改computed”本身不算“依赖变化”,自然没效果。

能给computed加setter吗?啥场景用?

可以!默认computed只有getter(负责计算值),但也能配置setter,让computed支持双向修改

啥场景需要setter?

比如做一个“全名”功能:用户可以输入“姓+名”(如“张三”),也能分别修改“姓”和“名”,这时候用computed的setter拆分赋值很方便。

代码示例:

import { ref, computed } from 'vue'  
const firstName = ref('张')  
const lastName = ref('三')  
const fullName = computed({  
  // getter:计算全名  
  get() {  
    return firstName.value + lastName.value  
  },  
  // setter:拆分全名到姓和名  
  set(newValue) {  
    // 假设用户输入“李四”,拆分成firstName='李', lastName='四'  
    const [first, last] = newValue.split('')  
    firstName.value = first  
    lastName.value = last  
  }  
})  
// 场景1:通过getter获取全名  
console.log(fullName.value) // 输出“张三”  
// 场景2:通过setter修改全名  
fullName.value = '李四'  
console.log(firstName.value) // 输出“李”  
console.log(lastName.value) // 输出“四”  

这种“双向联动”的场景,用computed的setter比写多个方法简洁多了~

依赖多个响应式数据时,computed咋工作?

Vue3的computed自动追踪所有依赖的响应式数据,只要其中任意一个变化,就会重新计算。

实战:购物车总价计算

假设购物车数据是这样的响应式数组:

import { reactive, computed } from 'vue'  
const cart = reactive([  
  { id: 1, price: 10, quantity: 2 },  
  { id: 2, price: 20, quantity: 3 }  
])  
const totalPrice = computed(() => {  
  return cart.reduce((sum, item) => {  
    return sum + item.price * item.quantity  
  }, 0)  
})  
console.log(totalPrice.value) // 10*2 + 20*3 = 80  
// 修改其中一个商品的quantity  
cart[0].quantity = 3  
console.log(totalPrice.value) // 10*3 + 20*3 = 90  
// 新增商品  
cart.push({ id: 3, price: 15, quantity: 2 })  
console.log(totalPrice.value) // 90 + 15*2 = 120  

可以看到,不管是修改已有商品的属性,还是新增商品(改变cart数组本身),computed都会自动感知变化,重新计算总价,这就是Vue的“响应式追踪”在起作用~

实战:用computed做列表搜索过滤

很多项目里需要“输入关键词,实时过滤列表”,用computed特别顺手。

步骤拆解:

  1. 定义响应式的搜索关键词(用户输入的内容)。
  2. 定义原始列表数据(比如从接口获取的数组)。
  3. computed根据关键词过滤列表,生成“过滤后的数据”。

代码示例:

<template>  
  <input v-model="searchQuery" placeholder="搜索商品" />  
  <ul>  
    <li v-for="item in filteredList" :key="item.id">{{ item.name }}</li>  
  </ul>  
</template>  
<script setup>  
import { ref, computed } from 'vue'  
// 原始商品列表(假设从接口拿到的)  
const products = ref([  
  { id: 1, name: 'Vue3实战' },  
  { id: 2, name: 'JavaScript进阶' },  
  { id: 3, name: '前端工程化' }  
])  
// 搜索关键词(双向绑定到输入框)  
const searchQuery = ref('')  
// 计算属性:过滤后的列表  
const filteredList = computed(() => {  
  // 转成小写,做不区分大小写的搜索  
  const query = searchQuery.value.toLowerCase()  
  return products.value.filter(product => {  
    return product.name.toLowerCase().includes(query)  
  })  
})  
</script>  

用户输入时,searchQuery变化 → computed自动重新过滤列表 → 页面实时更新,整个过程不用手动写“监听输入、调用过滤函数”的逻辑,computed帮我们自动做了~

computed里能写异步操作吗?为啥?

不能直接写异步!因为computed的设计是“同步返回计算结果”,而异步操作(比如Promiseasync/await)没法立刻返回值。

那需要异步计算属性咋办?

得结合refwatch手动实现“异步版计算属性”,举个例子,要根据用户ID异步获取用户信息:

import { ref, watch } from 'vue'  
const userId = ref(1)  
const userInfo = ref(null)  
// 用watch监听userId变化,触发异步请求  
watch(userId, async (newId) => {  
  const res = await fetch(`/api/user/${newId}`)  
  userInfo.value = await res.json()  
})  
// 初始加载  
watch(userId, { immediate: true })  

这里userInfo是响应式数据,依赖userId的变化触发异步请求,虽然不是直接用computed,但实现了“基于响应式数据的异步计算”效果~

computed的核心价值

  • 自动响应:依赖的响应式数据变了,自动重新计算。
  • 性能优化:依赖不变时复用缓存结果,减少不必要的计算。
  • 逻辑复用:把复杂的“数据推导逻辑”封装成计算属性,让模板和脚本更简洁。

现在再回头看开头的问题,是不是清晰多了?下次写Vue3代码时,遇到“需要根据已有数据生成新值、且希望自动更新”的场景,别忘用computed呀~

(如果还有其他疑问,比如computedwatch的区别、更复杂的依赖场景,评论区留言,下次展开讲~)

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门