Skip to content
On this page

watch(侦听器)用来监听某个数据的变化,然后执行一些"副作用"

和 computed 有什么区别?

| | computed | watch | | 做什么 | 根据数据算一个新值出来 | 数据变了,干一件事 | | 返回 | 必须返回一个值 | 不返回值,执行操作 | | 用途 | 格式化、过滤、拼接 | 发请求、存本地、调第三方库 | | 本质 | 派生数据 | 副作用处理 | 💡 Tip:一句话区别 computed:数据变了,算出新结果。 watch:数据变了,去做某件事。

基本用法

vue
<template>
  <input v-model="keyword" placeholder="搜索">
  <p>结果:{{ result }}</p>
</template>
<script>
export default {
  data() {
    return {
      keyword: '',
      result: ''
    }
  },
  watch: {
    keyword(newVal, oldVal) {               // 新值在前,旧值在后
      console.log(`从 "${oldVal}" 变为 "${newVal}"`)
      this.result = `搜索:${newVal}`
    }
  }
}
</script>

每次你输入文字 → keyword 变化 → watch 里的函数自动执行 → result 更新 → 页面刷新。 📝 Note:参数顺序keyword(newVal, oldVal)新值在前,旧值在后。别写反了。

deep — 深度监听

默认情况下,watch 只监听对象引用的变化(地址变了没有),不监听对象内部属性的变化。

vue
<script>
export default {
  data() {
    return {
      user: { name: '张三', age: 18 }
    }
  },
  watch: {
    user: {
      handler(newVal) {
        console.log('user 变了', newVal)
      },
      deep: true          // 开启深度监听
    }
  }
}
</script>

开启 deep: true 后,修改 user.nameuser.age 也会触发 watch。 ⚠️ Warning:deep 有性能代价deep: true 会递归遍历对象所有属性,对象很大会影响性能。只在确实需要监听嵌套属性时才开。

immediate — 立即执行

默认情况下,watch 只在数据变化时才触发。如果你需要在页面加载时就执行一次,加 immediate: true

vue
<script>
export default {
  watch: {
    keyword: {
      handler(newVal) {
        console.log('当前值:', newVal)
      },
      immediate: true     // 组件创建时立即执行一次
    }
  }
}
</script>

监听对象中的某个属性

如果只想监听对象的某个属性,而不是整个对象:

javascript
watch: {
  'user.name'(newName) {           // 用引号包起来,加点号
    console.log('名字变了:', newName)
  }
}

实际例子:防抖搜索

vue
<template>
  <div>
    <input v-model="keyword" placeholder="搜索用户">
    <ul>
      <li v-for="user in filteredUsers" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      keyword: '',
      users: [
        { id: 1, name: '张三' },
        { id: 2, name: '李四' },
        { id: 3, name: '王五' }
      ],
      filteredUsers: [],
      timer: null
    }
  },
  watch: {
    keyword() {
      clearTimeout(this.timer)                // 清除上一次定时器
      this.timer = setTimeout(() => {
        this.filteredUsers = this.users.filter(
          u => u.name.includes(this.keyword)
        )
      }, 300)                                  // 300ms 后才真正搜索
    }
  },
  created() {
    this.filteredUsers = this.users            // 初始显示全部
  }
}
</script>

新手常见问题

Q:computed 和 watch,我该用哪个? A:先想"我需要的是一个值,还是一个动作"——如果是值用 computed,是动作用 watch。 Q:watch 里能监听 computed 吗? A:可以。computed 的值变了也能被 watch 监听到。 Q:能不能同时监听多个数据? A:在选项式 API 中,每个数据单独写一个 watch。在组合式 API 中可以用数组:

javascript
watch([keyword, category], ([newKw, newCat]) => { ... })

下一步: 💡 Tip:Composition API 写法(Vue 3)

vue
<script setup>
import { ref, watch } from 'vue'
const keyword = ref('')
watch(keyword, (newVal, oldVal) => {
  console.log(`${oldVal} 变为 ${newVal}`)
})
</script>

watch 作为函数调用而非配置对象。另有 watchEffect(自动追踪依赖,立即执行)。 详见: