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

Vue3 计算属性与监听器:computed、watch、watchEffect 用法解析

在 Vue 开发中,计算属性(computed)和监听器(watch、watchEffect)是处理响应式数据的核心工具。Vue3 不仅保留了 Vue2 中的核心功能,还新增了 watchEffect 简化监听逻辑。本文将通过实战案例,详细讲解三者的用法、差异及最佳实践,帮你高效处理数据依赖与更新逻辑。

一、计算属性 computed:依赖数据的 “自动更新器”

计算属性基于其依赖的响应式数据自动计算结果,且会缓存计算结果 —— 只有当依赖数据变化时,才会重新计算,避免重复执行复杂逻辑。

1. 基础用法:只读计算属性

最常见的场景是基于已有数据生成新数据(如拼接字符串、计算总和)。

实战示例:拼接全名

<template><div><input v-model="firstName" placeholder="姓"><input v-model="lastName" placeholder="名"><p>全名:{{ fullName }}</p></div>
</template><script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')// 只读计算属性:依赖 firstName 和 lastName
const fullName = computed(() => {console.log('计算全名(仅依赖变化时执行)')return `${firstName.value}·${lastName.value}`
})
</script>

核心特点

  • 缓存机制:若 firstName 和 lastName 未变化,多次访问 fullName 只会返回缓存结果,不会重新执行函数
  • 响应式依赖:自动追踪依赖的响应式数据,依赖变化时自动更新
  • 只读性:默认情况下,计算属性是只读的,无法直接修改(如 fullName.value = '李·四' 会报错)
2. 进阶用法:可读写计算属性

当需要通过计算属性修改依赖数据时,可定义 get(读取)和 set(修改)方法,实现 “双向绑定”。

实战示例:通过全名修改姓和名

<template><div><input v-model="firstName" placeholder="姓"><input v-model="lastName" placeholder="名"><p>全名:{{ fullName }}</p><button @click="changeFullName">修改为“李·四”</button></div>
</template><script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')// 可读写计算属性
const fullName = computed({// 读取时执行get() {return `${firstName.value}·${lastName.value}`},// 修改时执行set(newValue) {// 拆分新值,更新依赖数据const [newFirst, newLast] = newValue.split('·')firstName.value = newFirst || ''lastName.value = newLast || ''}
})// 修改计算属性
const changeFullName = () => {fullName.value = '李·四'
}
</script>

适用场景

  • 表单双向绑定:通过计算属性统一处理表单值的读写(如格式化日期、处理特殊字符)
  • 复杂数据转换:修改计算属性时,自动同步更新多个依赖数据

二、监听器 watch:精准监听数据变化

watch 用于显式监听一个或多个响应式数据,当数据变化时执行自定义逻辑(如发送请求、更新 DOM)。Vue3 中的 watch 支持监听 refreactive 对象、函数返回值等多种数据类型。

1. 场景一:监听 ref 基本类型数据

监听 ref 定义的基本类型数据(如 numberstring),直接传入数据即可。

<template><div><p>计数:{{ count }}</p><button @click="count.value++">+1</button></div>
</template><script setup>
import { ref, watch } from 'vue'
const count = ref(0)// 监听 ref 基本类型数据
watch(count, (newVal, oldVal) => {console.log(`计数从 ${oldVal} 变为 ${newVal}`)// 场景:计数达到 10 时发送通知if (newVal >= 10) {alert('计数已达到 10!')}
})
</script>
2. 场景二:监听 ref 引用类型数据

监听 ref 定义的对象 / 数组时,默认仅监听地址变化(如替换整个对象)。若需监听内部属性变化,需手动开启 deep: true

<script setup>
import { ref, watch } from 'vue'
const user = ref({ name: '张三', age: 18 })// 监听 ref 对象内部属性变化(需开启 deep)
watch(user, (newVal, oldVal) => {console.log('用户信息变化:', newVal)
}, { deep: true })// 修改对象内部属性(触发监听)
const changeAge = () => {user.value.age++
}// 替换整个对象(触发监听,无需 deep)
const changeUser = () => {user.value = { name: '李四', age: 20 }
}
</script>
3. 场景三:监听 reactive 对象数据

监听 reactive 定义的对象 / 数组时,默认自动开启深度监听,无需手动设置 deep: true

<script setup>
import { reactive, watch } from 'vue'
const user = reactive({ name: '张三', age: 18 })// 监听 reactive 对象(默认深度监听)
watch(user, (newVal) => {console.log('用户年龄变化:', newVal.age)
})// 修改对象内部属性(触发监听)
const changeAge = () => {user.age++
}
</script>
4. 场景四:监听对象中的单个属性

若只需监听对象中的某个属性(而非整个对象),需通过函数返回值的方式指定监听目标,避免不必要的深度监听,提升性能。

<script setup>
import { reactive, watch } from 'vue'
const user = reactive({ name: '张三', age: 18, address: { city: '北京' } })// 监听 user.age(基本类型属性)
watch(() => user.age, (newVal) => {console.log('年龄变化:', newVal)
})// 监听 user.address.city(嵌套对象属性)
watch(() => user.address.city, (newVal) => {console.log('城市变化:', newVal)
})
</script>
5. 场景五:监听多个数据

同时监听多个响应式数据,将它们放入数组中即可,回调函数的参数会按数组顺序返回新值和旧值。

<script setup>
import { ref, watch } from 'vue'
const firstName = ref('张')
const lastName = ref('三')// 监听多个数据
watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {console.log(`姓从 ${oldFirst} 变为 ${newFirst}`)console.log(`名从 ${oldLast} 变为 ${newLast}`)console.log(`全名:${newFirst}${newLast}`)
})
</script>

三、新特性 watchEffect:自动追踪依赖的 “懒人监听器”

watchEffect 是 Vue3 新增的监听器,它会自动追踪函数内部的响应式依赖,无需显式指定监听目标,适合 “依赖不明确” 或 “依赖较多” 的场景。

1. 基础用法:自动追踪依赖
<template><div><p>水温:{{ temp }}℃</p><p>水位:{{ height }}cm</p><button @click="temp++">水温+1</button><button @click="height++">水位+1</button></div>
</template><script setup>
import { ref, watchEffect } from 'vue'
const temp = ref(0)
const height = ref(0)// watchEffect:自动追踪 temp 和 height 依赖
watchEffect(() => {console.log(`当前水温:${temp.value}℃,水位:${height.value}cm`)// 场景:水温≥50℃ 或 水位≥20cm 时发送报警if (temp.value >= 50 || height.value >= 20) {alert('警告:水温或水位超标!')}
})
</script>

核心特点

  • 自动执行:watchEffect 会在创建时立即执行一次,之后依赖变化时再次执行
  • 自动追踪:无需指定监听目标,函数内部用到的响应式数据都会被追踪
  • 无新旧值:回调函数没有 newVal 和 oldVal 参数,仅关注当前值
2. 停止监听

watchEffect 返回一个停止函数,调用该函数可手动停止监听,避免内存泄漏(如组件卸载时)。

<script setup>
import { ref, watchEffect, onUnmounted } from 'vue'
const count = ref(0)// 创建 watchEffect 并获取停止函数
const stopWatch = watchEffect(() => {console.log('计数:', count.value)
})// 组件卸载时停止监听
onUnmounted(() => {stopWatch()
})// 手动停止监听(如计数达到 10 时)
const stopWhenCount10 = () => {if (count.value >= 10) {stopWatch()alert('监听已停止')}
}
</script>

四、computed、watch、watchEffect 对比与最佳实践

特性computedwatchwatchEffect
核心用途依赖数据计算新值监听特定数据,执行副作用自动追踪依赖,执行副作用
依赖追踪自动追踪依赖显式指定监听目标自动追踪函数内依赖
执行时机依赖变化时计算数据变化时执行创建时立即执行,依赖变化再执行
缓存机制有(依赖不变时返回缓存)无(每次变化都执行)无(每次依赖变化都执行)
新旧值无(仅返回当前值)有(newVal、oldVal)无(仅当前值)
适用场景数据转换、拼接、过滤精准监听、需新旧值对比依赖较多、无需新旧值对比
最佳实践建议
  1. 数据计算用 computed:当需要基于已有数据生成新数据(如全名、总价、过滤列表),且不需要副作用时,优先用 computed,利用其缓存机制提升性能。

  2. 精准监听用 watch:当需要监听特定数据,且需要对比新旧值(如表单值变化、路由参数变化),或需要手动控制深度监听时,用 watch

  3. 自动追踪用 watchEffect:当需要执行副作用(如发送请求、操作 DOM),且依赖较多或不明确时,用 watchEffect,简化代码(如页面初始化时加载数据)。

  4. 避免过度使用 watch:不要用 watch 实现计算属性的功能(如 watch(count, () => { doubleCount.value = count.value * 2 })),这种场景下 computed 更简洁、高效。

  5. 清理副作用:在 watch 和 watchEffect 中若有副作用(如定时器、事件监听),需在组件卸载时清理(如 onUnmounted 中停止定时器),避免内存泄漏。

五、总结

computed、watch、watchEffect 是 Vue3 处理响应式数据的三大核心工具,它们各有侧重:

  • computed 是 “数据加工机”,专注于数据计算与缓存;
  • watch 是 “精准哨兵”,专注于特定数据的变化监听;
  • watchEffect 是 “智能管家”,专注于自动追踪依赖的副作用执行。
http://www.dtcms.com/a/536906.html

相关文章:

  • 题解:P14307 【MX-J27-T4】点灯
  • 网站关键词一般设置几个北京一家专门做会所的网站
  • 语文建设投稿网站wordpress静态cdn
  • 精品数据分享 | 锂电池数据集(一)新能源汽车大规模锂离子电池数据集
  • 01.LLM的背景知识
  • 17-21自增,自减,逻辑运算符,非布尔值的与或非,赋值运算符
  • 感兴趣可以看看使用xtrabackup 备份与恢复MySQL数据完整操作过程
  • 数据库安装卸载及作业
  • termux下python编程尝试,转换全能扫描王生成pdf文件
  • 做用户名和密码网站页面设计最简单的企业网站
  • wordpress设置数字形链接报404长沙做网站seo
  • 山区农产品售卖系统
  • 做微信的网站有哪些永久免费企业建站官网大全
  • 如何在linux抓包tcpdumpwireshark如何使用
  • FFmpeg 基本数据结构 AVCodec分析
  • QtQuick3D入门(2):材质 material
  • 怎么做网上卖菜网站酒店管理专业建设规划
  • 20251027 Prism.Unity依赖注入Demo
  • MES系统:论工单计划在智能制造中的核心串联作用​
  • 【C语言】程序控制结构
  • 厦门做网站哪家公司好非交互式网站可以做商城吗
  • OpenSSL3.5.2实现SM3数据摘要生成
  • 现代机器人学习入门:一份来自Hugging Face与牛津大学的综合教程开源SOTA资源库
  • 2D SLAM 主流算法推荐汇总和扫地机应用场景
  • 运维实战:SSL 证书故障避坑指南(精简版)
  • google网站管理员中心wordpress 字号 插件
  • 南通智能模板建站群晖wordpress安装
  • 网站建设时图片和文字北京网站定制报价
  • YOLOv5核心代码深度解析
  • SELinux 安全机制