第5集丨Vue 江湖 —— 监视属性/侦听属性

Vue 提供了一种更通用的方式来观察和响应 Vue实例上的数据变动:侦听属性,也成为监视属性

一、基本使用

监视属性watch:

  1. 当被监视的属性变化时,回调函数handler自动调用,进行相关操作。
  2. 监视的属性必须存在,才能进行监视。
  3. 监视的两种写法
    a. new Vue时传入watch配置
    b. 通过vm.$watch来动态实现监视

1.1 watch配置监视

下面案例中,我们通过watch配置属性来给isHuoguo 添加监视,当isHuoguo发生变化时,所配置的handler()函数会调用。

注意:这里有一个属性immediate,其默认值为false。当配置为true时,页面初始化时,让handler调用一下。

<div id="root">
    <h2>今天我们去吃{{info}}</h2>
    <button @click="change">切换</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.isHuoguo = !this.isHuoguo;
            }
        },
        watch: {
            isHuoguo:{
                immediate:true,//默认为false,初始化时,让handler调用一下。
                handler(newValue, oldValue) {
                    console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
                }
            }
        }
    })
</script>

效果图如下:

在这里插入图片描述

1.2 vm.$watch动态监视

不仅可以给属性(即data中定义的)添加监视,也可以给计算属性添加监视。

下面例子,我们通过vm.$watch 方式,来动态给计算属性info添加监视:

<div id="root">
    <h2>今天我们去吃{{info}}</h2>
    <button @click="change">切换</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.isHuoguo = !this.isHuoguo;
            }
        },
        watch: {
            isHuoguo:{
                // immediate:true,//默认为false,初始化时,让handler调用一下。
                handler(newValue, oldValue) {
                    console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
                }
            }
        }
    })

    // 监视计算属性
    vm.$watch('info',{
        // immediate:true,//默认为false,初始化时,让handler调用一下。
        handler(newValue, oldValue) {
            console.log("info计算属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
        }
    })

</script>

在这里插入图片描述

1.3 深度监视(deep watch)

深度监视(deep watch):

  1. Vue中的watch默认不监测对象内部值的改变(只监测一层结构)
  2. 配置deep:true可以监测对象内部值的改变(可以监测多层结构),Vue默认不开启deep,是为了提供效率。
  3. Vue自身可以监测对象内部值的改变,但是Vue提供的watch默认不可以。
  4. 使用watch时,要根据数据的具体结构,决定是否采用深度监视。

使用方式:

  • 监视多级结构中某个属性的变化,例如下面例子中numbers.a
  • 监视多级结构中所有属性的变化,numbers:{deep:true,handler(){}}
<div id="root">
    <h3>今天我们去吃{{info}}</h3>
    <button @click="change">切换</button>
    <hr>
    <h3>a的值是{{numbers.a}}</h3>
    <button @click="numbers.a++">点击a++</button>
    <hr>
    <h3>b的值是{{numbers.b}}</h3>
    <button @click="numbers.b++">点击b++</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true,
            numbers:{
                a:1,
                b:1
            }
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.isHuoguo = !this.isHuoguo;
            }
        },
        watch: {
            isHuoguo:{
                handler(newValue, oldValue) {
                    console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
                }
            },
            // 监视多级结构中某个属性的变化
            "numbers.a": {
                handler() {
                    console.log("a被改变了!");
                }
            },
            // 监视多级结构中所有属性的变化
            numbers:{
                deep:true,
                handler() {
                    console.log("numbers改变了!");
                }
            }
            
        }
    })

   
</script>

1.4 简写形式

当所配置的监视,只需要handler,不需要其他配置的时候,才可以使用简写形式,使用函数来代替。

两类简写形式:

  • watch配置里的简写
  • 动态添加监视的简写
<div id="root">
    <h3>今天我们去吃{{info}}</h3>
    <button @click="change">切换</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.isHuoguo = !this.isHuoguo;
            }
        },
        watch: {
            /* isHuoguo:{
                deep:true,
                immediate:true,
                handler(newValue, oldValue) {
                    console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
                }
            }, */
            // 简写形式
            isHuoguo(newValue, oldValue) {
                
                console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
            }
        }
    })

    // 动态添加监视的简写
    vm.$watch('isHuoguo',function(newValue, oldValue){
        console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
    })
   
</script>

二、computed和watch的对比

计算属性(computed)和监视属性(watch)之间的区别:

  1. computed能完成的功能,watch都可以完成
  2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。

两个重要的原则
3. 被Vue所管理的函数,最好写成普通函数,这样this的指向才是vm组件实例对象
4. 所有不被Vue管理的函数(定时器的回调函数(setTimeout)、ajax的回调函数、Promise的回调函数等),最好写成箭头函数,这样this的指向才是 vm组件实例对象

2.1 使用watch实现setTimeout操作

下面代码,使用了watch实现setTimeout操作,有一点需要注意的是,setTimeout所指定的回调函数要使用箭头函数(因为箭头函数本身没有this),否则this指向window了,而不再是vm实例。

<div id="root">
    <div class="row">姓:<input type="text" v-model="firstName"></div>
    <div class="row">名:<input type="text" v-model="lastName"></div>
    <div class="row">全名:<span>{{fullName}}</span></div>
</div>

<script>
    const vm = new Vue({
        el:'#root',
        data() {
            return {
                firstName: '小',
                lastName: '三',
                fullName:'小-三'
            };
        },
        methods:{
            
        },
        watch:{
            firstName(val) {
                setTimeout(() => {  //这里不能写成普通函数,否则this指向window了
                    console.log(this);  //vm实例对象
                    this.fullName = val + "-" + this.lastName;
                }, 1000);
                
            },
            lastName(val){
                this.fullName = this.firstName + "-" + val;
            }
        }
    });
</script>

2.2 用computed无法实现setTimeout

computed计算属性,无法实现setTimeout想要的功能,如下错误代码所示:

<div id="root">
    <div class="row">姓:<input type="text" v-model="firstName"></div>
    <div class="row">名:<input type="text" v-model="lastName"></div>
    <div class="row">全名:<span>{{fullName}}</span></div>
    
</div>

<script>
    const vm = new Vue({
        el:'#root',
        // 对于Vue来说,data中配置的就是属性。
        // 计算属性:用现有的属性去加工、计算生成一个全新的属性。和属性分开放
        data:{
            firstName: '小',
            lastName: '三'
        },
        computed:{
            fullName() {
                console.log('get被调用了!');
                // console.log(this);
                setTimeout(() => {
                    return this.firstName+'-'+this.lastName
                }, 1000);
                
            }
        }
        
    });
</script>

三、其他注意事项

3.1 vue devtools的bug

当页面上没有用到某个计算属性时,vue devtools调试工具会出现一个bug:不会显示数据的变化了。例如下面代码

<div id="root">
    <h2>今天我们去吃米饭</h2>
    <button @click="change">切换</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.isHuoguo = !this.isHuoguo;
            }
        },
    })
</script>

点击切换按钮,工具中显示的datacomputed 不发生变化,其实数据已经发生了改变。可以通过控制台中输入vm.info来查看。如下图所示:

在这里插入图片描述
在这里插入图片描述

3.2 @xxx=yyy格式

这里的yyy不是事件名称,而是一些简单的语句。例如:@click="isHuoguo = !isHuoguo;count++;"

下面的案例中,两个按钮均可实现功能。不过需要注意的是,执行语句比较复杂的时候不建议直接写在yyy中。

<div id="root">
    <h2>今天我们去吃{{info}}--切换次数{{count}}</h2>
    <button @click="change">切换</button>
    <button @click="isHuoguo = !isHuoguo;count++">切换2</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true,
            count:0,
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.count++;
                this.isHuoguo = !this.isHuoguo;
            }
        },
    })
</script>

3.3 将window传入data中

window传入data中,实现alert弹框。如下代码所示:

<div id="root">
    <h2>今天我们去吃{{info}}--切换次数{{count}}</h2>
    <button @click="change">切换</button>
    <button @click="isHuoguo = !isHuoguo;count++">切换2</button>
    <button @click="window.alert(1)">弹出alert</button>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            isHuoguo:true,
            count:0,
            window      //相当于window:window
        },
        computed:{
            info() {
                return this.isHuoguo?'火锅':'南京大排档';
            }
        },
        methods: {
            change() {
                this.count++;
                this.isHuoguo = !this.isHuoguo;
            }
        },
    })
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值