一、计算属性(computed)

computed 用于依赖其他响应式数据而动态计算出一个新值。

<script setup>
import { ref, computed } from 'vue'

const score = ref(85)

// 1. 基础用法:默认是【只读】的(传入一个 getter 函数)
const grade = computed(() => {
  if (score.value >= 90) return '优秀'
  if (score.value >= 80) return '良好'
  return '及格'
})

// 2. 高级用法:【可读可写】的计算属性
const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    // 当你执行 plusOne.value = 10 时,会触发 set,从而逆向改变它依赖的 count
    count.value = val - 1
  }
})
</script>

computed 的缓存机制

如果用一个普通函数 getGrade() 代替 computed,在模板里调用有什么区别?

  • 答案缓存(Cache)

  • 底层原理computed 内部有一个脏检查开关 _dirty。只有当它依赖的响应式数据(如 score)发生改变时,_dirty 才会变成 true,在下一次读取时重新计算。如果依赖的数据没变,无论你读取 grade 多少次,它都会直接从内存中读取上一次计算好的结果,绝对不重复执行函数。而普通函数在每次页面重新渲染时,都会被强行执行一次

二、侦听器

当数据发生变化,你想执行一段异步逻辑(比如发 Ajax 请求、写入 LocalStorage、改 Redis 缓存前台数据),就需要用到侦听器。

1. watch

watch 必须要明确指定侦听谁,具有懒执行(默认第一次不触发)和能拿到旧值(oldValue)的特点。

<script setup>
import { ref, reactive, watch } from 'vue'

const count = ref(0)
const user = reactive({ name: '张三', config: { theme: 'dark' } })

// 场景一:侦听单个 ref 
watch(count, (newValue, oldValue) => {
  console.log(`count变了:${oldValue} -> ${newValue}`)
})

// 场景二:侦听 reactive 对象里的【某一个具体属性】(必须写成函数形式!)
watch(() => user.name, (newName) => {
  console.log('用户名变了:' + newName)
})

// 场景三:深度侦听配置
watch(user, (newUser) => {
  console.log('user对象里有属性变了(默认深度侦听)')
}, { deep: true, immediate: true }) // deep:深度侦听 immediate: true 变成页面一进来就立即先执行一次
</script>

2. watchEffect

watchEffect 不需要指定具体的变量,它会自动追踪你在代码块里用到了谁,只要用到了谁,谁变了它就自动触发。

<script setup>
import { ref, watchEffect } from 'vue'

const userId = ref(1)
const data = ref(null)

// 自动追踪 userId,一进来就会立即执行一次(因为要收集依赖)
watchEffect(async () => {
  // 只要 userId.value 发生改变,这个回调就会自动重新执行,去拉取新数据
  const res = await fetch(`https://api.com/user/${userId.value}`)
  data.value = await res.json()
})
</script>

3. watch vs watchEffect

特性 watch watchEffect
依赖追踪 显式指定,你写谁它才听谁。 隐式自动收集,代码里读了谁它就听谁。
首次执行 默认是懒执行(除非加 immediate: true)。 页面一加载必然立即执行一次
新旧值 可以同时拿到 newValueoldValue 拿不到旧值,只能拿到当前最新的值。
适用场景 适用于知道明确的变量变了要干啥,且需要对比新旧值的场景。 适用于多个依赖连续联动,或者一上来就要执行的异步操作。

更多推荐