计算属性与侦听器:处理响应式数据
计算属性与侦式数据:处理响应式数据
计算属性和侦听器都是处理响应式数据的方式,但适用场景不同。这篇说说怎么选。
计算属性: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>
当 firstName 或 lastName 变化时,fullName 自动更新。
computed 的好处
- 缓存:依赖不变时不重新计算
- 模板里直接用:不需要调用函数
<!-- 不用计算属性:每次渲染都执行函数 -->
<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:立即执行,自动追踪依赖,适合需要立即运行+自动追踪的场景
基础语法阶段到这里就结束了。下一阶段学路由和状态管理。
