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

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

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

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

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

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

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

实战示例:拼接全名

<template>
  <div>
    <input v-model="firstName" placeholder="姓">
    <input v-model="lastName" placeholder="名">
    <p>全名:{{ fullName }}</p>
  </div>
</template>

<script setup>
import { ref, ***puted } from 'vue'
const firstName = ref('张')
const lastName = ref('三')

// 只读计算属性:依赖 firstName 和 lastName
const fullName = ***puted(() => {
  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, ***puted } from 'vue'
const firstName = ref('张')
const lastName = ref('三')

// 可读写计算属性
const fullName = ***puted({
  // 读取时执行
  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>

四、***puted、watch、watchEffect 对比与最佳实践

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

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

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

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

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

五、总结

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

  • ***puted 是 “数据加工机”,专注于数据计算与缓存;
  • watch 是 “精准哨兵”,专注于特定数据的变化监听;
  • watchEffect 是 “智能管家”,专注于自动追踪依赖的副作用执行。
转载请说明出处内容投诉
CSS教程网 » Vue3 计算属性与监听器:computed、watch、watchEffect 用法解析

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买