09Vue3 侦听器详解

一、侦听器概念

侦听器(Watchers)是 Vue 3 中用于观察和响应数据变化的机制。当需要在数据变化时执行异步操作或复杂逻辑时,使用侦听器比计算属性更合适。

二、基本用法

1. 使用 watch 函数

import { ref, watch } from 'vue'

// 示例1:侦听单个响应式数据
const count = ref(0)

watch(count, (newValue, oldValue) => {
  console.log(`count从 ${oldValue} 变为 ${newValue}`)
})

// 示例2:侦听多个数据源
const name = ref('张三')
const age = ref(25)

watch([name, age], (newValues, oldValues) => {
  console.log('name或age发生了变化')
  console.log('新值:', newValues)
  console.log('旧值:', oldValues)
})

2. 在组件中使用

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

// 侦听ref
const count = ref(0)

// 侦听reactive对象的属性
const user = reactive({
  name: '张三',
  age: 25,
  address: {
    city: '北京'
  }
})

// 侦听单个属性(需要函数返回值)
watch(
  () => user.name,
  (newName, oldName) => {
    console.log(`姓名从 ${oldName} 变为 ${newName}`)
  }
)

// 深度侦听对象
watch(
  () => user,
  (newUser, oldUser) => {
    console.log('user对象发生变化')
  },
  { deep: true }
)

// 立即执行
watch(
  count,
  (newValue) => {
    console.log('当前count值:', newValue)
  },
  { immediate: true }
)
</script>

三、选项配置

watch(
  source,
  callback,
  {
    // 深度侦听(用于对象/数组)
    deep: true,
    
    // 立即执行回调
    immediate: true,
    
    // 回调执行时机
    flush: 'pre' | 'post' | 'sync', // 默认 'pre'
    
    // 调试用
    onTrack: (event) => {},
    onTrigger: (event) => {}
  }
)

四、watchEffect 函数

watchEffect 会自动追踪其内部依赖,并在依赖变化时重新执行。

import { ref, watchEffect } from 'vue'

const count = ref(0)
const double = ref(0)

// 自动追踪count依赖
watchEffect(() => {
  double.value = count.value * 2
  console.log(`double值更新为: ${double.value}`)
})

// 停止侦听
const stop = watchEffect(() => {
  // 逻辑...
})

// 手动停止
stop()

watchEffect 的清理机制

watchEffect((onCleanup) => {
  const timer = setInterval(() => {
    console.log('定时器执行')
  }, 1000)
  
  // 清理函数
  onCleanup(() => {
    clearInterval(timer)
    console.log('清理定时器')
  })
})

五、watch vs watchEffect

特性watchwatchEffect
依赖收集 显式指定 自动收集
初始执行 需要 immediate: true 立即执行
新旧值 可以获取 无法获取
适用场景 特定数据变化时执行 响应式副作用

 

六、实际应用示例

1. 搜索功能

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

const searchQuery = ref('')
const searchResults = ref([])
const isLoading = ref(false)

// 防抖搜索
let timeoutId

watch(searchQuery, (newQuery) => {
  clearTimeout(timeoutId)
  
  if (!newQuery.trim()) {
    searchResults.value = []
    return
  }
  
  isLoading.value = true
  
  timeoutId = setTimeout(async () => {
    try {
      const response = await fetch(`/api/search?q=${newQuery}`)
      searchResults.value = await response.json()
    } catch (error) {
      console.error('搜索失败:', error)
    } finally {
      isLoading.value = false
    }
  }, 300)
})
</script>

2. 表单验证

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

const form = reactive({
  email: '',
  password: '',
  confirmPassword: ''
})

const errors = reactive({})

// 监听表单变化进行验证
watch(
  () => [form.email, form.password, form.confirmPassword],
  () => {
    errors.email = !form.email.includes('@') ? '邮箱格式不正确' : ''
    errors.password = form.password.length < 6 ? '密码至少6位' : ''
    errors.confirmPassword = 
      form.password !== form.confirmPassword ? '两次密码不一致' : ''
  },
  { immediate: true }
)
</script>

七、性能优化建议

  1. 避免深度侦听:除非必要,尽量使用浅层侦听

  2. 及时停止侦听:组件卸载时确保停止不必要的侦听

  3. 使用防抖/节流:高频变化的数据使用防抖

  4. 合理使用 watchEffect:依赖明确时使用 watch

八、注意事项

  1. 侦听器回调默认在组件更新前执行(flush: 'pre'

  2. 异步回调中访问 DOM 时,使用 flush: 'post'

  3. 侦听响应式对象的属性时,需要使用 getter 函数

// 正确
watch(() => obj.count, (val) => console.log(val))

// 错误(不会触发)
watch(obj.count, (val) => console.log(val))

九、组合式 API 中的使用

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

// 可以多次调用
watch(source1, callback1)
watch(source2, callback2)
watchEffect(effect1)
</script>

侦听器是 Vue 3 响应式系统的核心功能之一,合理使用可以处理各种数据变化带来的副作用,但要注意避免过度使用导致性能问题。

posted @ 2026-02-10 15:21  麻辣~香锅  阅读(2)  评论(0)    收藏  举报