Vue中的watch和computed

174 阅读2分钟

watch

watch是侦听时间(以前叫监听)它具备handler默认函数,当监视属性发生变化时,他就会自动调用,类似于coomputed中的getter和setter,在watch中还可以监视多个源,甚至可以监视多级结构中的属性的变化,当需要监视的属性中存在多级结构时,也可以开启深度监视功能来检测属性的变化。watch的调用可以卸载Vue实例中的wacth配置项中,也可以在外边调用¥watch属性来进行设置,如果watch的配置中只有handler函数,也可以将此监视属性进行简写。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>监视属性</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h2>天气很热{{info}}</h2>
        <button @click="changWeather">切换天气</button>
        <button @click="isHot = !isHot">切换天气</button>
        <hr/>
        <h2>{{number.a}}</h2>
        <button @click="number.a++">点我a++</button>
        <hr/>
        <h2>{{number.b}}</h2>
        <button @click="number.b++">点我b++</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                isHot: true,
                number: {
                    a: 1,
                    b: 1
                }
            },
            computed: {
                info() {
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                changWeather() {
                    this.isHot = !this.isHot
                }
            },
            watch: {
                //也可以监视计算属性
                isHot: {
                    //hander和computed中的属性一样,当isHot变化是他会自动执行handler函数
                    handler(newValue, oldValue) {
                        console.log('isHot被修改了', newValue, oldValue);
                    }
                },
                //简写
                isHot() {
                    console.log('isHot被修改了', newValue, oldValue);
                },
                //检测多级结构中的某个属性的变化
                'number.a': {
                    handler() {
                        console.log('a被改变了');
                    }
                },
                //监视多级结构中的所有属性的变化
                number: {
                    deep: true, //深度监视
                    handler() {
                        console.log('number改变了');
                    }
                }
            }
        })
        vm.$watch('isHot', {
            //hander和computed中的属性一样,当isHot变化是他会自动执行handler函数
            handler(newValue, oldValue) {
                console.log('isHot被修改了', newValue, oldValue);
            }
        })
        vm.$watch('isHot', function() {
            console.log('isHot被修改了', newValue, oldValue);
        })
    </script>
</body>

</html>

computed

computed是计算属性,实质是将属性再一次进行加工,内置了getter和setter,其原理是来自于数据代理中的Object.defineProperty(),当计算属性中只有getter时,可以就将其简写成函数的形式,计算属性和methods的区别是自动调用getter函数作为返回值,还会做一次缓存,减少请求次数,但是,当其所依赖的数据发生变化是,就会从新调用getter函数,其中调用函数的时机分为两种:第一个时间调用: 第二个是所依赖的数据发生变化时;

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>计算属性</title>
    <!-- 计算属性是指在现有的data属性上进行再次加工 -->
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="root">
        <button @click="show1($event)">点我</button>
        <hr/>
        <span></span><input type="text" v-model="firstName"><br/><br/>
        <span></span><input type="text" v-model="lastName"><br/><br/>
        <span>全名</span><span>{{fullName}}</span>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                firstName: 1,
                lastName: 2
            },
            methods: {
                show1(event) {
                    console.log(event);
                }
            },
            computed: {
                // 完整写法
                fullName: {
                    // 自动调用getter函数作为返回值,还会做一次缓存
                    // 第一个时间调用:初次调用fullName时  第二个是所依赖的数据发生变化时
                    get() {
                        return this.firstName + '-' + this.lastName
                    },
                    set(value) {
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }
                //简写
                /*   fullName: function() {
                      return this.firstName + '-' + this.lastName
                  } */
            }
        })
    </script>
</body>

</html>

区别

watch可以开启异步任务,而且在开启异步任务的同时要是用箭头函数使得this的指向于Vue实例对象(因为settimeout、ajax都是由js引擎管理的,但是箭头函数是没有this指向的,谁调用箭头函数,this指向谁,由此开启任务时,this指向调用者Vue实例),而在操作Vue实例中的对象是要写成普通函数的样子。computed所依赖的时函数return值,所以对于计算属性来说并不能设置异步任务。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="root">
        <span>姓:</span><input type="text" v-model="firstName"><br/><br/>
        <span>名:</span><input type="text" v-model="lastName"><br/><br/>
        <span>全名computed:</span><span>{{fullName}}</span>
        <span>全名watch:</span><span>{{fullName1}}</span>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                firstName: 1,
                lastName: 2,
                fullName1: '1 - 2',
            },
            computed: {
              //计算属性不能开启异步任务,他依靠的是return的返回值
                //完整写法
                fullName: {
                    // 自动调用getter函数作为返回值,还会做一次缓存
                    // 第一个时间调用:初次调用fullName时  第二个是所依赖的数据发生变化时
                    get() {
                        return this.firstName + '-' + this.lastName
                    },
                    set(value) {
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }
                //简写
                /* fullName: function() {
                     return this.firstName + '-' + this.lastName
                 } */
            },
            watch: {
              //watch可以开启异步任务
                firstName(newValue) {
                    setTimeout(() => {
                        this.fullName1 = newValue + '-' + this.lastName;
                    }, 1000);
                },
                lastName(newValue) {
                    this.fullName1 = this.firstName + '-' + newValue;
                }
            }
        })
    </script>
</body>

</html>