Vue3 计算属性|从基础缓存到可读写

作为一名大三正在啃 Vue3 的学生,今天刚啃完计算属性(computed)的核心知识点,踩了几个小坑也理清了关键区别,赶紧整理成笔记,既方便自己复习,也希望能帮到同样在学 Vue 的小伙伴~

一、为什么需要计算属性?

先抛个场景:如果我们需要在模板里展示「任务完成数量」,直接写{{list.filter((item) =>item.done).length}}虽然能实现,但模板里塞太多逻辑会变得臃肿、难维护、性能低;如果用普通函数调用,又会有重复计算的问题。

而计算属性就是为了解决这个问题而生的 ------ 它基于依赖缓存,只在依赖变化时重新计算,既简洁又高效。

1. 看看基础的使用

XML 复制代码
<script setup lang="ts">
import { ref, computed } from 'vue'

// 模拟任务列表完成情况
const list = ref([{done:true},{done:false},{done:true}])

// 计算属性:统计完成的任务数
const donecount = computed(()=>{
  console.log('donecount(计算属性)执行了')
  return list.value.filter((item) => item.done).length
})

// 普通函数:同样统计完成的任务数
function donecount2 () {
  console.log('donecount2(普通函数)执行了')
  return list.value.filter((item) => item.done).length
}
</script>

<template>
  <!-- 直接写模板表达式(不推荐,逻辑冗余) -->
  任务完成数量:{{ list.filter((item) => item.done).length }}
  <br>
  
  <!-- 计算属性调用(无括号) -->
  计算属性版:{{ donecount }} - {{ donecount }}
  <br>
  
  <!-- 普通函数调用(必须加括号) -->
  普通函数版:{{ donecount2() }} - {{ donecount2() }}
</template>

当我们运行,打开界面,去控制台查看时会发现只输出了一遍"donecount(计算属性)执行了",而"donecount2(普通函数)执行了"却执行了两遍,为什么呢?


二、核心优势:缓存机制(计算属性 vs 普通函数)

这是计算属性最关键的特性,也是和普通函数最大的区别!

1. 首次渲染的差异

运行上面的代码,控制台打印结果:

donecount(计算属性)执行了

donecount2(普通函数)执行了

donecount2(普通函数)执行了

  • 计算属性donecount虽然在代码中写了两次,实际只执行了一次。
  • 普通函数donecount()写了两次,实际上也调用了两次------因为函数每次调用都会重新。

2. 依赖变化时的差异

如果我们加上一个修改按钮

XML 复制代码
<script setup lang="ts">
// 新增:修改依赖的函数
function modify () {
  list.value[0].done = false
}
</script>

<template>
  <button @click="modify">修改第一个任务状态</button>
</template>

点击按钮后,list的依赖发生变化:

  • 计算属性 donecount会重新执行 1 次(因为依赖的 list 变了);
  • 普通函数 donecount2() 只有再次调用时才会执行,但每次调用依然是重新计算。

3. 结论

  • 计算属性:基于依赖缓存,依赖不变时,多次访问只返回缓存结果,不重复计算;
  • 普通函数:无缓存,每次调用都会重新执行函数体。

三、进阶:计算属性如何传参?

计算属性本身是无参 的,直接写**computed((index) => {})** 会报错!那如果我们想根据索引取菜单名称(比如**menu(0)**取 首页),该怎么做?

答案:让计算属性返回一个函数,通过函数传参实现!

1. 示例

XML 复制代码
<script setup lang="ts">
import { reactive, computed } from 'vue'

// 模拟菜单列表
const menuList = reactive([
  {name:'首页'},
  {name:'新闻'}
]) 

// 计算属性返回函数,实现传参
const menu = computed(() => {
  // 这里的index就是我们要传的参数
  return (index:number)=>{
    return menuList[index]?.name 
  }
})
</script>

<template>
  菜单1:{{ menu(0) }} <!-- 输出:首页 -->
  菜单2:{{ menu(1) }} <!-- 输出:新闻 -->
</template>

这个写法既保留了计算属性对 menuList依赖监听 ( menuList变了会重新计算),又实现了参数传递


四、高级用法:可读写的计算属性(完整形式)

默认的计算属性是只读 的(只有 getter),如果我们需要给计算属性赋值(比如通过 v-model 绑定),就要用 getset 完整形式。

举个拆分姓名的例子:输入[张三 李四],自动拆分成 firstName 和 lastName;修改 firstName/lastName,计算属性也会同步更新

1. 案例

XML 复制代码
<script setup lang="ts">
import { ref, computed } from 'vue'

const firstName = ref('')
const lastName = ref('')

// 可读写的计算属性
const msg2 = computed({
  // 读取值时触发(getter)
  get(){
    return firstName.value + lastName.value
  },
  // 赋值时触发(setter)
  set(value:string){
    // 把输入的字符串按空格拆分成姓和名
    const [n1,n2] = value.split(' ')
    firstName.value = n1 || ''
    lastName.value = n2 || ''
    console.log('赋值的内容:', value);
  }
})
</script>

<template>
  输入姓名:<input v-model="msg2"> 
  完整名字: {{ msg2 }}
  <!-- 测试:输入「张三 李四」,firstName会变成「张三」,lastName变成「李四」 -->
</template>

注意:普通的计算属性(只写 getter)是只读的,如果直接赋值会报错,比如:

XML 复制代码
const msg1 = computed(()=>{
  return 'xxx'
})
// 报错:Set operation on key "msg1" failed: target is readonly.

五、总结:计算属性的使用场景 & 注意事项

1. 什么时候用计算属性?

  • 需要基于现有数据做 派生计算(比如统计、拼接、过滤);
  • 希望避免重复计算,提升性能(缓存特性);

2. 核心注意点

  • 计算属性必须有返回值;
  • 依赖必须是响应式数据(ref/reactive),否则不会触发重新计算;
  • 只读计算属性用单函数形式,可读写用 get/set 形式;
  • 传参通过返回函数实现,不要直接给 computed 传参;

今天的笔记就到这啦~Vue 的计算属性看似简单,实则藏了不少细节,尤其是缓存和传参这两个点,踩过坑才知道有多重要。

相关推荐
❆VE❆1 分钟前
React基础篇(三):项目中 React 基础核心知识点实战
前端·javascript·react.js·前端框架
Hello--_--World2 分钟前
React 的核心设计理念是什么?并列举三大核心特性。
javascript·react.js·ecmascript
Momo__4 分钟前
contenteditable 深度剖析:让网页元素「活」起来
前端·html
淸湫4 分钟前
前端JavaScript:NaN、undefined、null详解
javascript
栀栀栀栀栀栀7 分钟前
强迫症犯了(゚∀゚) 2026/4/26
前端·javascript·vue.js
RPGMZ9 分钟前
RPGMakerMZ 获取敌人攻击时属性 用于画UI或属性克制
javascript·游戏引擎·rpgmz·rpgmakermz
Lucas_coding21 分钟前
【xiaozhi-客户端】xiaozhi-web-client 连接客户端 6位有效码
前端
谪星·阿凯23 分钟前
电商系统Web渗透测试实战指南
前端·网络·安全·web安全·网络安全
Ruihong25 分钟前
Vue 的 :deep/:global/:slotted 怎么转成 React ?一份对照指南?
vue.js·react.js·面试
redreamSo31 分钟前
HeyGen 开源了一个"用 HTML 写视频"的框架,我研究了一下,发现事情没那么简单
前端·开源·音视频开发