当前位置: 首页 > news >正文

计算属性与侦听器

计算属性与侦听器

  • computed:从现有数据“算”出新数据(有缓存,无副作用)
  • watch:监听数据变化,执行副作用(如请求、日志、操作上报)

1. 计算属性 computed

为什么需要computed?

模板中直接写复杂表达式会导致臃肿、重复、不可复用。
把“根据现有数据算出新数据”的逻辑放在<script setup>中,模板只负责渲染。

基本用法

import{ref,computed}from'vue'constkeyword=ref('')constusers=ref([...])// 源数据constfilteredUsers=computed(()=>{returnusers.value.filter(user=>user.name.includes(keyword.value))})

三个要点

  1. 模板中直接使用,不要加.value(自动解包):v-for="user in filteredUsers"
  2. 脚本中必须用.value读取值:filteredUsers.value.length
  3. 只读:不能给计算属性赋值,要改变结果就修改它依赖的源数据

缓存特性

  • computed 会缓存计算结果,只有当依赖的响应式数据变化时才重新计算
  • 多次使用同一个计算属性,只会执行一次计算(后续读缓存)

对比普通方法

  • 方法每次被调用都会重新执行(无论依赖是否变化)
  • 模板渲染时多次调用方法就会执行多次,无缓存

类比:computed 像电子价目牌(商品不变就不动),方法像收银员每接一个任务就重新计算

误区:计算函数里如果使用了非响应式数据(如Date.now()),Vue 无法感知变化,缓存不会失效。

典型应用:搜索 + 筛选

同时根据关键字和状态过滤列表,两个条件用 AND 叠加:

constkeyword=ref('')conststatusFilter=ref('全部')constfilteredUsers=computed(()=>{returnusers.value.filter(user=>{constmatchKeyword=keyword.value===''||user.name.includes(keyword.value)||user.dept.includes(keyword.value)constmatchStatus=statusFilter.value==='全部'||user.status===statusFilter.valuereturnmatchKeyword&&matchStatus})})

模板中直接遍历filteredUsers,人数统计直接用filteredUsers.length


2. 侦听器 watch

与 computed 的区别

  • computed 是纯计算,不应包含副作用(请求、日志等)
  • watch 专门用于数据变化时执行副作用

口诀:能算就用 computed,要动才用 watch

基本用法

import{ref,watch}from'vue'constkeyword=ref('')watch(keyword,(newVal,oldVal)=>{console.log(`关键词从「${oldVal}」变为「${newVal}`)// 可以在这里:发请求、记日志、保存数据等})

回调参数:(新值, 旧值)

监听多个数据源

watch([keyword,statusFilter],([newKeyword,newStatus],[oldKeyword,oldStatus])=>{// 任一数据变化都触发})

防抖处理(debounce)

连续触发时,只执行最后一次(如输入暂停 500ms 后再发起请求):

lettimer=nullwatch(keyword,(newVal)=>{clearTimeout(timer)timer=setTimeout(()=>{// 执行上报或请求},500)})

清除上一次的定时器,保证只有停止输入超过指定时间才会执行。

选项:immediate(立即执行)

  • 默认 watch 只在数据第一次变化后才触发
  • 设置immediate: true可在页面初始化时立即执行一次回调(此时oldValueundefined
watch(statusFilter,(newVal)=>{// 初始化时也会执行},{immediate:true})

常用于:进入页面立即加载数据、记录初始状态等。

选项:deep(深度监听)

  • 普通 watch 只监听引用类型变量的引用变化(如数组整体替换)
  • 如果需要监听对象内部属性或数组元素变化,设置deep: true
watch(users,()=>{// 当 users 数组内某个对象的属性被修改时触发},{deep:true})

注意事项

  • deep有性能损耗,大对象或深层嵌套对象要小心使用
  • 深度监听时回调中的新旧值是同一个引用,无法获得变化前的快照(newVal === oldVal
  • 如果需要获取旧值,自己在外层保存快照

监听 reactive 对象的某个属性(getter 形式)

import{reactive,watch}from'vue'conststate=reactive({name:'张三',age:30})watch(()=>state.name,(newVal,oldVal)=>{// 只监听 name 属性,无需 deep})

这种写法更精确、性能更好。


3. computed vs watch 选型总结

computedwatch
用途派生数据(计算新值)执行副作用(动作)
返回值有返回值,可直接在模板使用无返回值,只执行回调
缓存有(依赖不变不重复计算)无(每次变化都触发)
触发条件依赖变化时自动重新计算被监听数据变化时执行回调
典型场景搜索过滤、列表统计、格式化显示数据变化请求接口、日志上报、防抖搜索、配置保存
依赖多个数据多个响应式数据都可作为依赖可监听单个或多个数据源
异步支持不能包含副作用适合放异步请求

选择原则

  • 需要得到一个新数据→ computed
  • 需要在数据变化时做一件事→ watch

两者常配合使用,并非二选一。


4. 关键代码速查

搜索筛选(computed)

constfilteredUsers=computed(()=>{returnusers.value.filter(user=>{constmatchKeyword=keyword.value===''||user.name.includes(keyword.value)||user.dept.includes(keyword.value)constmatchStatus=statusFilter.value==='全部'||user.status===statusFilter.valuereturnmatchKeyword&&matchStatus})})

联动上报(watch + 防抖)

lettimer=nullwatch([keyword,statusFilter],([newKeyword,newStatus])=>{clearTimeout(timer)timer=setTimeout(()=>{addLog(`筛选条件已变化:关键字「${newKeyword}」、状态「${newStatus}`)},500)})

immediate + deep 示例

// 页面打开立即记录当前筛选状态watch(statusFilter,(newStatus)=>{addLog(`当前筛选状态为「${newStatus}`)},{immediate:true})// 监听用户列表内部变化watch(users,()=>{addLog('用户列表数据发生变化')},{deep:true})

5. 常见错误排查

现象原因解决
模板中filteredUsers.value报错模板自动解包,不需要.value直接写filteredUsers
搜索无效,列表不变v-for仍遍历源数据users改为filteredUsers
给计算属性赋值报错computed 只读修改依赖的源数据
点击“切换状态”日志不触发没有加deep: true监听对象/数组内部变化需加deep
每输入一个字符都上报缺少防抖clearTimeout/setTimeout控制
刷新页面没有初始化日志忘记immediate: true在 watch 配置中添加
deep 监听时新、旧值相同深度监听的新旧值是同引用需要旧值请自行深拷贝保存
http://www.jsqmd.com/news/1369976/

相关文章:

  • 华硕笔记本终极性能优化指南:G-Helper免费工具完全掌控你的设备
  • SA4556 36V 高耐压 2A 锂电池线性充电芯片|带 OVP、NTC 温度检测单节锂电充电方案
  • 2026年优选临沂诚信的激光切割机厂商哪家靠谱 - 装修教育财税推荐2026
  • 2026年海口值得信赖的二手房出售中介机构我房网(海口运营中心) - 热点品牌推荐
  • DOS命令实战指南:从基础操作到自动化批处理脚本
  • 国产射频测试新突破:SL22便携式信号源22.6GHz 宽频覆盖解析 频率覆盖:45MHz~22.6GHz,一台设备覆盖多场景需求 LMX2820 射频信号源发生器 扫频正弦波
  • 跨平台图形移植开发短记:日常巡检少走弯路
  • Claudecode的安装使用教程
  • JAVA+SQL电子通讯录带系统托盘(论文+源代码)
  • 2026年广州番禺正规漏水检测推荐 实用选择指南及服务详解 - 盛隆防水
  • 2026年广州南沙正规漏水检测推荐 靠谱机构挑选全指南 - 盛隆防水
  • AI Agent协作系统构建指南:从双AI直播到工程化实践
  • 寻沧州本地的3PE 防腐螺旋钢管厂认准沧州复久管道有限公司(沧州服务中心) - 热点品牌推荐
  • 2026 年当下,潮州口碑好的国标土工膜公司电话,别再乱买防渗膜了!这玩意儿才是工程人要找的合规硬通货,能省出半年耗材费 - 企业推荐官-
  • 如何快速解决Switch大文件存储问题:NSC_BUILDER完整使用指南
  • 15天掌握轻型门式钢架设计核心技能
  • 从代码到智能:开发者如何将AI能力工程化为可交付的软件产品
  • 大语言模型应用框架控制层与方向层架构对比:OpenProse、NLAH与AGE
  • DDrawCompat终极指南:3步让经典游戏在现代Windows完美运行
  • iPad无纸化学习配件选购指南:从核心三件套到高效工作流
  • C++ MFC实现二维图形变换:从矩阵原理到可视化编程实践
  • 2026年8月小型污水处理设备/屠宰污水处理设备行业靠谱厂家_山东顺江环保装备有限公司 - 行业平台推荐
  • SpringBoot+MyBatis反射异常解析与解决方案
  • 2026 年新消息:兴宁知名的豆包AI获客代运营公司推荐,你以为做实体获客还在烧广告费?这玩意儿竟能让门店客源翻3倍还不用自己盯 - 行业推荐官-2
  • 异地就医报销比例咋算?骨折跨市转运专车预约流程 - AZJ888
  • 从零构建AI编程智能体:基于LangChain的任务分解与工具调用实践
  • 移动端游戏开发实战:用Trae Solo在手机上完成2D平台跳跃游戏Demo
  • SpringBoot+Vue3智慧教室管理系统设计与实现
  • Android Drawable - gradient
  • AI Agent安全护栏设计:基于LangGraph构建可控自主智能体