Vue的watch侦听属性详解

335 阅读3分钟

前言

上次接触watch还是面试的时候,由于第一次学Vue蜻蜓点水加搁置时间很久了,所以只知道watch是监听状态的。今天这篇文章,用于详细的记录Vue中的watch监视属性。

题外话

阻止Vue在启动时生成生产提示 Vue.config.productionTip=false

代码案例1-基于侦听属性的天气案例

    <!-- 天气案例 -->
    <div id="weather">
        <h2>今天的天气情况:{{info}}</h2>
        <button @click="changeWeather">切换天气</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#weather',
            data: {
                isHot: true
            },
            computed: {
                info() {
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                changeWeather() {
                    this.isHot = !this.isHot
                }
            },
            watch: {
                info: {
                    immediate: true,
                    handler(newValue, oldValue) {
                    console.log('info被修改', newValue, oldValue)
                    }
                }
            }
        })
    </script>

代码解析

天气的切换是因为切换isHot的值,watch的值是配置对象 在watch下面监视isHot,当值发生变化控制台输出提醒。

watch: {
                isHot: {  
                    immediate: true,
                    handler(newValue, oldValue) {
                    console.log('isHot被修改', newValue, oldValue)
                    }
                }
         }

handler当isHot发生改变时调用,immediate:true可以实现初始化时让handler调用一下,注意immediate是写在handler的前面,否则不生效。 watch不仅可以监视isHot,也可以监视info,如代码案例1

watch监视info.png 第一次监测info第二个值undefined是因为还未发生改变,单击切换天气后数据发生改变,第二个值不再是undefined。

watch检测info切换天气后不再是undefined.png

如果不写watch,也可以在创建实例后在实例外面写


vm$watch('isHot',{
    immediate:true,
    handler:(newValue,oldValue){
        console.log('isHot被改',newValue,oldValue)
    }
})

如果明确知道监视谁就写watch,如果写完了想到要用watch可以用下面直接调取API的方式。

代码案例2-基于深度侦听的天气案例

深度监视

(1).Vue中的watch默认不监测对象内部值的变化(一层),Vue自身可以监测对象内部值的变化 (2).配置deep:true可以监测对象内部值改变(多层) (3).使用watch时根据数据的具体结构,决定是否采用深度监视,

深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。 ------Vue官方文档

  <div id="weather">
        <h2>今天的天气情况:{{info}}</h2>
        <button @click="changeWeather">切换天气</button>
        <hr />
        <h3>a:{{numbers.a}}</h3>
        <button @click="numbers.a++">a+1</button>
        <h3>a:{{numbers.b}}</h3>
        <button @click="numbers.b++">b+1</button>
        <button @click="numbers={a:666,b:888}">彻底替换numbers</button>
        numbers.a.b.c.d.e

    </div>
    <script>
        const vm = new Vue({
            el: '#weather',
            data: {
                isHot: true
            },
            numbers: {
                a: 1,
                b: 1,
                c: {
                    d: {
                        e: 100
                    }
                }
            },
            computed: {
                info() {
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                changeWeather() {
                    this.isHot = !this.isHot
                }
            },
            watch: {
                inHot: {
                    immediate: true,
                    deep: true,
                    handler(newValue, oldValue) {
                        console.log('inHot被修改', newValue, oldValue)
                    }
                }
            }
        })
    </script>

watch可以简写成如下

        vm.$watch('isHot', {
            immediate: true,
            deep: true,
            handler(newValue, oldValue) {
                console.log('inHot被修改', newValue, oldValue)
            }
        })

computed和watch的对比-姓名案例

watch侦听属性实现


    <div id="name">
        姓:<input type="text" v-model="firstName"><br /><br />
        名:<input type="text" v-model="lastName"><br /><br />
        姓名:<span>{{fullName}}</span>
    </div>

    <script>
        const vm = new Vue({
            el: '#name',
            data: {
                firstName: '张',
                lastName: '三',
                fullName: '张-三'
            },
            watch: {
                firstName(newValue) {
                    console.log(this);
                    this.fullName = newValue + '-' + this.lastName
                },
                lastName(val) {
                    this.fullName = val + '-' + this.firstName
                }

            }
        })
    </script>

computed完整实现姓名案例

    <div id="name">
        姓:<input type="text" v-model="firstName"><br /><br />
        名:<input type="text" v-model="lastName"><br /><br />
        测试:<input type="text" v-model="x"><br /><br />
        姓名:<span>{{fullName}}</span>
        <!-- <button @click="demo">点我</button> -->
    </div>

    <script>
        const vm = new Vue({
            el: '#name',
            data: {
                firstName: '张',
                lastName: '三',
                x: 'hello'
            },
            computed: {
                fullName: {
             
                    get() {
                        console.log('get被调用了')
                        console.log(this) 
                        return this.firstName + this.lastName
                      
                    },
                   
                    set(value) {
                        console.log('set', value)
                        const arr = value.split('_')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }
            }

        })
    </script>

计算属性computed的简写

fullName(){
    console.log('get被调用')
    return this.firstName+'-'+this.latName
}

姓名案例新的需求:姓发生改变全名延迟5秒显示。 方法:在姓的方法中添加settimeout

firstName(val) { setTimeout(() => { this.fullName = val + '-' + this.lastName }, 5000); },

在watch里面可以开启异步任务,但是计算属性不行,在computed加setTimeout会报错 如图所示

计算属性添加演示定时器代码.png

计算属性延迟定时器报错.png 控制台没有报错信息,但全名显示不出来,原因是因为return的值是箭头函数的,fullName没有返回值了(undefined)。如图,fullName的返回值应该是在下面的新的return语句,计算属性不可开启异步任务来维护数据,watch可以,watch根据自己写的代码进行。

计算属性不能开启异步任务.png

定时器写成箭头函数

定时器的回调箭头函数不是普通函数,定时器指定的函数不是Vue所管理的函数,定时器在fullname中开启的,如果写普通函数,this是window,定时器指定的回调时js引擎帮忙会回调的,箭头函数没有自己的this就往外找,就是firstName的this(vm)

computed和watch的区别

1.computed能完成的功能,watch都可以完成 2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。 两个重要的小原则: 1.所有Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象 2.所有不被Vue管理的函数(定时器的回调函数,ajax的回调函数,Promise的回调函数)最好写出箭头函数,这样this的指向才是vm或组件实例对象。

感觉this指向这个知识点也很重要要再去复习一下哈哈哈

要想清楚Vue里面的this首先要明白JavaScript里面this指向的问题。

JavaScript中的this指向问题

            window.color = 'yellow';
            let a = {
                color: 'black'
            };

            function expressColor() {
                console.log(this.color)
            }

            expressColor();

            a.expressColor = expressColor;
            a.expressColor();//
  

运行结果是yellow,black。 分析一下,在全局上下文中调用expressColor(),this指向window,this.color相当于window.color,所以输出是yellow。 而把expressColor()赋值给a之后再调用a.expressColor,this会指向a,this.color相当于a.color,输出black。