计算属性与侦听器:处理响应式数据

计算属性与侦式数据:处理响应式数据

计算属性和侦听器都是处理响应式数据的方式,但适用场景不同。这篇说说怎么选。

计算属性:computed

用于基于已有数据计算出新数据,结果会被缓存。

<script setup lang="ts">
import { ref, computed } from 'vue'

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

// 计算属性
const fullName = computed(() => {
  return lastName.value + firstName.value
})

console.log(fullName.value) // 张三
</script>

firstNamelastName 变化时,fullName 自动更新。

computed 的好处

  1. 缓存:依赖不变时不重新计算
  2. 模板里直接用:不需要调用函数
<!-- 不用计算属性:每次渲染都执行函数 -->
<p>{{ getFullName() }}</p>

<!-- 用计算属性:只在依赖变化时计算 -->
<p>{{ fullName }}</p>

计算属性 vs 方法

<script setup lang="ts">
// 计算属性(有缓存)
const fullName = computed(() => firstName.value + lastName.value)

// 方法(每次渲染都调用)
function getFullName() {
  return firstName.value + lastName.value
}
</script>

区别是:

  • 计算属性:依赖不变时,返回缓存结果
  • 方法:每次调用都重新执行

侦听器:watch

用于监听数据变化,然后执行副作用(比如发请求)。

<script setup lang="ts">
import { ref, watch } from 'vue'

const count = ref(0)

// 监听 count 变化
watch(count, (newValue, oldValue) => {
  console.log(`count 从 ${oldValue} 变成了 ${newValue}`)
})

// 初始化时不会执行,默认 lazy
</script>

watch 默认是懒执行的:初始化时不会执行,只有值变化才执行。

watch 的参数

<script setup lang="ts">
const count = ref(0)
const user = ref({ name: '张三', age: 25 })

// 监听单个 ref
watch(count, callback)

// 监听多个 ref
watch([count, user], ([newCount, newUser], [oldCount, oldUser]) => {
  // ...
})

// 监听对象某个属性
watch(() => user.value.name, (newName) => {
  console.log('名字变了:', newName)
})

// 深度监听
watch(user, (newUser) => {
  console.log('用户变了', newUser)
}, { deep: true })
</script>

watchEffect:立即执行的侦听

watchEffect 会立即执行,依赖变化时重新运行:

<script setup lang="ts">
import { ref, watchEffect } from 'vue'

const count = ref(0)

watchEffect(() => {
  // 立即执行,访问了 count,所以会自动监听
  console.log('count 是', count.value)
})
</script>

适合需要"立即执行 + 自动追踪依赖"的场景。

什么时候用哪个

场景用什么
根据已有数据计算新值computed
数据变化时执行副作用(请求、DOM 操作)watch
需要立即执行 + 自动追踪依赖watchEffect

实战例子

computed:过滤列表

<script setup lang="ts">
import { ref, computed } from 'vue'

const search = ref('')
const list = ref([
  { id: 1, name: '苹果' },
  { id: 2, name: '香蕉' },
  { id: 3, name: '橘子' }
])

// 根据搜索词过滤
const filteredList = computed(() => {
  return list.value.filter(item =>
    item.name.includes(search.value)
  )
})
</script>

<template>
  <input v-model="search" placeholder="搜索" />
  <ul>
    <li v-for="item in filteredList" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

watch:防抖搜索

<script setup lang="ts">
import { ref, watch } from 'vue'

const search = ref('')
const result = ref(null)

// 防抖:等用户停止输入 300ms 后再搜
watch(search, (newValue) => {
  if (!newValue) {
    result.value = null
    return
  }
  setTimeout(() => {
    fetchData(newValue)
  }, 300)
})
</script>

总结

  • computed:根据响应式数据计算新值,有缓存,适合模板中使用
  • watch:监听数据变化执行副作用,懒执行,适合发请求
  • watchEffect:立即执行,自动追踪依赖,适合需要立即运行+自动追踪的场景

基础语法阶段到这里就结束了。下一阶段学路由和状态管理。

最后更新 4/30/2026, 8:57:45 AM