返回 导航

Vue.js

hangge.com

Vue.js - 监听器watch的使用详解(深度监听、属性监听、立即执行、$watch)

作者:hangge | 2026-03-16 09:00
    在 data 属性中可以定义响应式数据,并在模板中使用。当响应式数据发生变化时,模板中对应的内容也会自动更新。但在某些情况下,需要监听某个响应式数据的变化,这时就需要使用监听器(watch)来实现了。 

一、基本用法

1,function 语法

(1)下面是一个 watch 的简单使用样例:
  • 有一个输入框(input),用户可在其中输入一个问题。 
  • 在代码中实时监听用户输入的问题,一旦输入的内容发生变化,就到服务器中查询答案(这里直接为 answer 变量重新赋值,模拟服务器返回答案)。 
<template>
    <div class="my-component">
        <input type="text" v-model="question">
        <div>{{ anwser }}</div>
    </div>
</template>
<script>
export default {
    name: 'MyComponent',
    data() {
        return {
            question: "",
            anwser: ""
        }
    },
    // 监听属性
    watch: {
        // 侦听question的变化
        // question :侦听的data中的属性的名称
        // newValue :变化后的新值
        // oldValue :变化前的旧值
        question: function (newValue, oldValue) {
            console.log("新值: ", newValue, "旧值", oldValue);
            // question 变化后调用 queryAnswer() 方法
            this.queryAnswer();
        }
    },
    // 方法
    methods: {
        queryAnswer() {
            this.anwser = `你的问题是:${this.question}? `;
        }
    },
}
</script>

(2)上面是 function 语法的完整写法,还可以简写为如下形式:
// 监听属性
watch: {
    // 侦听question的变化
    // question :侦听的data中的属性的名称
    // newValue :变化后的新值
    // oldValue :变化前的旧值
    question(newValue, oldValue) {
        console.log("新值: ", newValue, "旧值", oldValue);
        // question 变化后调用 queryAnswer() 方法
        this.queryAnswer();
    }
},

2,对象语法

对象语法和 function 语法的编写方式略有不同,但它们所实现的功能是相同的。
watch: {
    // 侦听question的变化
    // question :侦听的data中的属性的名称
    // newValue :变化后的新值
    // oldValue :变化前的旧值
    question: {
        handler(newValue, oldValue) {
            console.log("新值: ", newValue, "旧值", oldValue);
            // question 变化后调用 queryAnswer() 方法
            this.queryAnswer();
        }
    }
},

3,字符串语法

    下面是一个字符串语法样例,监听属性 question 的值是 queryAnswer 字符串。当 question 发生变化时,会触发 queryAnswer 函数的回调。
// 监听属性
watch: {
    question: 'queryAnswer'
},
// 方法
methods: {
    queryAnswer() {
        this.anwser = `你的问题是:${this.question}? `;
    }
},

4,数组语法

    下面样例监听属性 question 的值是一个数组,数组中的第一项为字符申语法、第二项是函数语法、第三项是对象语法。当 question 值发生改变时,会依次调用 handle1handle2handle3 函数。
// 监听属性
watch: {
    question: [
        'handle1',
        function handle2(newVal, oldVal) {
            console.log('handle2', newVal, oldVal)
        },
        {
            handler: function (newVal, oldVal) {
                console.log('handle3', newVal, oldVal)
            },
        }
    ]
},
// 方法
methods: {
    handle1() {
        console.log('handle1')
    }
}

5,$watch 的 API 语法

(1)Vue.js 还提供了 watchAPI 进行监听。例如我们可以在 created 生命周期中使用 this.$watch 进行监听,其使用语法为 this.$watch(source, callback, options)。 
  • source:要监听的源。 
  • callback:监听的回调函数。 
  • options:额外的选项,比如 deepimmediate。 

(2)下面样例使用 this.$watch 监听 data 属性中定义的对象类型变量 info
created() {
    this.$watch('info', function (newVal, oldVal) {
        console.log('watch', newVal, oldVal)
    }, { deep: true, immediate: true })
},

二、watch 配置选项

1,基本介绍

watch 对象语法的常见配置选项有以下几种:
  • handler:要监听的回调函数,当监听属性发生变化时会调用该函数。(这个在上面样例中已经演示了) 
  • deep:是否深度监听对象或数组中每个属性的变化,默认值是 false。 
  • immediate:是否立即执行回调函数,默认值是 false。 

2,deep 选项

(1)由于 deep 默认值为 false,即不会深度监听对象中属性的变化。下面样例运行后会发现:
  • 单击“改变 info”按钮,watch 能够监听到 info 变量的更新
  • 单击“改变 info.name”按钮,发现页面上显示的 name 已经更新,但是 watch 却没有检测到 info 对象的修改,即控制台不会打印出新旧 info 的信息。
  • 单击“改变改变 info.site.name”按钮,发现页面上显示的 info.site.name 已经更新,但是 watch 却没有检测到 info 对象的修改,即控制台不会打印出新旧 info 的信息。
<template>
    <div class="my-component">
        <h2>{{ info.name }}</h2>
        <h2>{{ info.site.name }}</h2>
        <button @click="changeSite">改变info</button>
        <button @click="changeSiteName">改变info.site</button>
        <button @click="changeSiteBookName">改变info.site.name</button>
    </div>
</template>
<script>
export default {
    name: 'MyComponent',
    data() {
        return {
            info: { name: "hangge", age: 18, site: { name: '航歌' } }
        }
    },
    // 监听属性
    watch: {
        // 侦听info对象的更新
        info: {
            handler: function (newInfo, oldInfo) {
                console.log("newValue:", newInfo, "oldValue:", oldInfo);
            }
        }
    },
    methods: {
        changeSite() {
            this.info = { name: "baidu", age: 18, site: { name: '百度' } }
        },
        changeSiteName() {
            this.info.name = "google";
        },
        changeSiteBookName() {
            this.info.site.name = "谷歌";
        }
    },
}
</script>

(2)如果我们启用 deep 选项对对象进行深度监听,那么在三个按钮上依次单击,可以发现 info 内部发生的改变都可以被 watch 监听到,即控制台会打印新旧 info 的信息。
watch: {
    // 侦听info对象的更新
    info: {
        handler: function (newInfo, oldInfo) {
            console.log("newValue:", newInfo, "oldValue:", oldInfo);
        },
        // 深度侦听 info 对象的更新(info内部发生的改变是可以侦听到的)
        deep: true
    }
},

3,immediate 选项

(1)immediate 选项可以让 handler 中定义的函数立即执行一次,在默认情况下,该函数只在监听的数据发生变化时才会回调。下面代码我在 watch 属性中的 info 对象多了 immediate:true 配置:
watch: {
    // 侦听info对象的更新
    info: {
        handler: function (newInfo, oldInfo) {
            console.log("newValue:", newInfo, "oldValue:", oldInfo);
        },
        // 深度侦听 info 对象的更新(info内部发生的改变是可以侦听到的)
        deep: true,
        immediate: true // 让handler中定义的函数立即执行一次
    }
},

(2)浏览器中运行代码,只需要简单地刷新浏览器,handler 中定义的函数就会立即执行一次:

附:仅监听对象中的某个属性

(1)前面提到,当需要监听一个对象时,可以使用 watch 选项。如果想要监听对象的引用的变化或者监听对象内部属性的变化,那么可以配置 deep 选项。
(2)除此之外,还可以直接监听对象中某个属性的变化,而不是监听整个对象。 比如下面样例,仅监听 info 对象中 name 属性的变化。
watch: {
    "info.name": {
        handler: function (newInfo, oldInfo) {
            console.log("newValue:", newInfo, "oldValue:", oldInfo);
        }
    }
},
评论

全部评论(0)

回到顶部