返回

Vue 3 中 Watch 无法监听对象属性:原因与解决方案

前端

在 Vue 3 中,Watch 无法监听对象属性的情况确实存在。让我们深入了解其背后的原因以及应对这一限制的有效解决方案。

问题根源

Vue 3 的 watch 功能默认只监听简单值类型(如字符串、数字、布尔值)的更改。对象属性在本质上是引用类型,这意味着 watch 仅跟踪引用本身的变化,而不是对象内部属性的更改。

解决方案

方法 1:深度监听

Vue 3 提供了一种特殊的 deep 选项,允许 watch 递归监听对象属性的更改。要启用此功能,请将 deep 设置为 true

watch: {
  user: {
    handler(newVal, oldVal) {
      // newVal 和 oldVal 都是包含属性变化的新旧对象
    },
    deep: true
  }
}

方法 2:Getter

Getter 函数为 watch 提供了一个在每次渲染期间检索最新属性值的机会。这使得 watch 可以跟踪对象属性的更改,即使属性没有明确赋值:

watch: {
  userName() {
    return this.user.name;
  }
}

方法 3:函数包裹

将对象属性包裹在函数中会创建一个新的可观察值。当函数被调用时,它会返回当前对象的属性值,从而允许 watch 监听任何更改:

watch: {
  userName() {
    return () => this.user.name;
  }
}

实例代码

以下示例演示了如何使用这些解决方案来监听 Vue 3 中的对象属性更改:

<template>
  <div>
    <input type="text" v-model="user.name">
  </div>
</template>

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

export default {
  setup() {
    const user = ref({ name: 'John' })

    // 使用深度监听
    watch(() => user.value.name, (newVal, oldVal) => {
      console.log(`深度监听:${oldVal} => ${newVal}`)
    }, { deep: true })

    // 使用 Getter
    watch(() => this.userName(), (newVal, oldVal) => {
      console.log(`Getter:${oldVal} => ${newVal}`)
    })

    // 使用函数包裹
    watch(() => {
      return this.user.name
    }, (newVal, oldVal) => {
      console.log(`函数包裹:${oldVal} => ${newVal}`)
    })

    return {
      user,
      userName
    }
  }
}
</script>

结论

尽管 Vue 3 的 watch 功能默认不监听对象属性的更改,但通过使用深度监听、getter 或函数包裹,开发人员可以轻松解决这一限制并监听对象属性的更改。这些解决方案可确保组件可以响应对象属性的动态更新,从而提高响应性和应用程序的整体可靠性。