watch 与搜索功能
博客首页想加一个搜索框:用户输入关键词,文章列表立刻过滤出标题匹配的文章。这个"监听输入变化并做出反应"的需求,正是 watch(侦听器) 的用武之地。本节先讲 watch 的常用写法,再实现完整的实时搜索。
watch 基本用法:监听一个响应式数据
watch 接收"要监听的数据"和"变化后的回调":
import { ref, watch } from 'vue'
const keyword = ref('') // 搜索关键词
watch(keyword, (newVal, oldVal) => {
console.log('关键词变化:', oldVal, '->', newVal)
})
在搜索框输入"vue"后控制台输出:关键词变化: -> vue(newVal 为新值,oldVal 为旧值)。
监听 getter:想听什么就听什么
要监听对象里的某个属性或计算出来的值,就传一个返回该值的函数:
const search = ref({ text: '' }) // 对象
// 第一个参数是函数:只有 text 变化才触发
watch(
() => search.value.text,
(newText) => console.log('搜索内容:', newText)
)
search 对象其它字段变化不会误触发。
深度监听与立即执行
- 监听整个对象时,内部属性变化默认不触发,需加
{ deep: true }:
watch(search, (newObj) => {
console.log('整个对象变了:', newObj)
}, { deep: true }) // 深层变化也能侦测到
- 想一进页面就执行一次(如先按空关键词显示全部),加
{ immediate: true }:
watch(keyword, (val) => {
loadList(val) // 首次进入和每次输入都执行
}, { immediate: true })
注意 deep 开销较大,能精确到 getter 就不要整对象 deep。
博客实时搜索实战
结合 v-model 与 watch 实现"输入即过滤":
<template>
<input v-model="keyword" placeholder="搜索文章标题..." />
<ul>
<li v-for="p in filteredPosts" :key="p.id">{{ p.title }}</li>
</ul>
</template>
<script setup>
import { ref, watch } from 'vue'
const keyword = ref('')
const posts = ref([
{ id: 1, title: 'Vue3 入门指南' },
{ id: 2, title: 'Pinia 状态管理' },
{ id: 3, title: 'Vue Router 路由详解' }
])
const filteredPosts = ref(posts.value) // 默认显示全部
watch(keyword, (val) => {
// 标题包含关键词就保留
filteredPosts.value = posts.value.filter(p => p.title.includes(val))
}, { immediate: true })
</script>
输入"Vue",列表立刻只剩第 1、3 篇;清空后恢复全部。
watch 与 computed 如何选择
- computed:由已有数据"派生"出新数据(如过滤结果),有缓存、更简洁:
// 同样的过滤用 computed 更合适
const filteredPosts = computed(() =>
posts.value.filter(p => p.title.includes(keyword.value))
)
- watch:数据变化后要"执行副作用",如请求接口、写日志、操作 DOM。 数据量小、纯前端过滤推荐 computed;要请求后端搜索接口则用 watch 触发,并可加防抖(节流)减少请求次数。
小结:watch 监听数据变化并执行副作用,getter/deep/immediate 覆盖常见场景;派生数据优先用 computed,需要"变化后做事"再用 watch。下一节把可复用的逻辑封装成 Composable。