Vue2入门之超详细教程九-监视属性

发布时间 2023-05-07 16:10:53作者: 李荣洋

1、简介

  监视属性watch

    1.当被监视的属性变化时,回调函数自动调用,进行相关操作

    2.监视的属性必须存在,才能进行监视!!

    3.监视的两种写法:

      (1) new Vue时传入watch配置

      (2) 通过vm.$watch监视

  深度监测:

    (1) Vue中的watch默认不监测对象内部值的改变(一层)

    (2) 配置deep:true可以监测对象内部值改变(多层)

  备注:

    (1) Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以

    (2) 使用watch时根据数据的具体结构,决定是否采用深度监视

  学习Vue之前最后会一些HTML和CSS的基础知识,HTML基础知识 传送门CSS基础知识 传送门

2、监视属性

1. 天气案例

  在vscode中创一个新目录,叫“08_监视属性”,在下面创建一个“1_计算属性方式实现.html”文件,在里面输入以下代码:

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        new Vue({

            el:'#root',

            data:{

                isHot:true

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            }

        })

    </script>

</body>

</html>

  该案例,当点击按钮时,会调用changeWeather方法,赋值isHotisHot的取反的值

2. 监视属性

第一种写法

  可以监视Vue中的属性,当发生变化时会被调用

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        new Vue({

            el:'#root',

            data:{

                isHot:true

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

            watch:{

                isHot:{

                    //初始化时立即调用一下

                    // immediate:true,

                    //handler什么时候调用?当IsHot发生改变时被调用,可以接收两个值,第一个为修改后,第二个为修改前

                    handler(newValue,oldValue){

                        console.log('isHot被修改该了',newValue,oldValue)

                    }

                }

            }

       

        })

    </script>

</body>

</html>

   使用场景:比如当气温低于15度是时,提醒多穿衣服:

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        new Vue({

            el:'#root',

            data:{

                isHot:true,

                temperature:20

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                    this.temperature--

                }

            },

            watch:{

                temperature:{

                    //初始化时立即调用一下

                    // immediate:true,

                    //handler什么时候调用?当IsHot发生改变时被调用,可以接收两个值,第一个为修改后,第二个为修改前

                    handler(newValue,oldValue){

                        console.log('isHot被修改该了',newValue,oldValue)

                        if(newValue < 15){

                            alert('天冷啦,多穿衣服')

                        }

                       

                    }

                }

            }

       

        })

    </script>

</body>

</html>

 第二种写法

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        const vm = new Vue({

            el:'#root',

            data:{

                isHot:true

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

       

        })

        vm.$watch('isHot',{

            handler(newValue,oldValue){

                console.log('isHot被修改该了',newValue,oldValue)

            }

        })

    </script>

</body>

</html>

 3. 深度监视

  以上监测都是针对一级属性监测,当存在多级属性时如何进行检测呢?

多级监测

  比如:numbers属性下存在两个属性ab,我们只针对a变动做检测

  再使用以上方式就不可以了,这会必须使用’numbers.a这种方式,注意这里不能直接简写为numbers.a必须用引号引起来,完整代码如下:

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

        <hr>

        <h3>a的值是{{numbers.a}}</h3>

        <button @click="numbers.a++">点我让a+1</button>

 

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        new Vue({

            el:'#root',

            data:{

                isHot:true,

                numbers:{

                    a:1,

                    b:1

                }

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

            watch:{

                'numbers.a':{

                    //handler什么时候调用?当IsHot发生改变时被调用,可以接收两个值,第一个为修改后,第二个为修改前

                    handler(newValue,oldValue){

                        console.log('a被改变了',newValue,oldValue)

                    }

                }

            }

       

        })

    </script>

</body>

</html>

深度监测

  以上面代码为例,如果想a或者b任意一个发生变化时都可以监测到,你可能想可以这样写:

            

        watch:{

                'numbers':{

                    handler(newValue,oldValue){

                        console.log('numbers被改变了',newValue,oldValue)

                    }

                }

            }

  明确告诉大家,这样是不可以的,如下图,这样写只会监测粉色线中的部分,并不会监测绿色内的部分

  像这种方式我们只需要加一个配置即可:

  deep:true,

  完整代码如下:

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

        <hr>

        <h3>a的值是{{numbers.a}}</h3>

        <button @click="numbers.a++">点我让a+1</button>

        <hr>

        <h3>b的值是{{numbers.b}}</h3>

        <button @click="numbers.b++">点我让b+1</button>

        <button @click="numbers={a:111,b:222}">彻底替换掉numbers</button>

 

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        new Vue({

            el:'#root',

            data:{

                isHot:true,

                numbers:{

                    a:1,

                    b:1

                }

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

            watch:{

                'numbers':{

                    deep:true,

                    handler(newValue,oldValue){

                        console.log('numbers被改变了',this.numbers.a,this.numbers.b)

                    }

                }

            }

       

        })

    </script>

</body>

</html>

4. 监测属性的简写形式

Vue中简写形式

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        new Vue({

            el:'#root',

            data:{

                isHot:true,

                numbers:{

                    a:1,

                    b:1

                }

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

            watch:{

                //正常写法

                // 'isHot':{

                //     //immediate:true, //初始化时让handler调用一下

                //     //deep:true, //深度监视

                //     handler(newValue,oldValue){

                //         console.log('isHot被改变了',this.numbers.a,this.numbers.b)

                //     }

                // }

                //简写形式

                isHot(){

                    console.log('isHot被改变了',this.numbers.a,this.numbers.b)

                }

            }

       

        })

    </script>

</body>

</html>

vm.$watch中简写形式

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        const vm = new Vue({

            el:'#root',

            data:{

                isHot:true,

                numbers:{

                    a:1,

                    b:1

                }

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

       

        })

        //正常写法

        // vm.$watch('isHot',{

        //     immediate:true,

        //     deep:true,

        //     handler(newValue,oldValue){

        //         console.log('isHot被修改了',newValue,oldValue)

        //     }

        // })

        //简写方式

        vm.$watch('isHot',function(newValue,oldValue){

            console.log('isHot被修改了',newValue,oldValue)

        })

    </script>

</body>

</html>

3、测试

  我们来检测一个不存在的属性’123’来看看效果

<!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 type="text/javascript" src="../js/development/vue.js"></script>

</head>

<body>

    <div id="root">

        <h2>今天天气很{{info}}</h2>

        <button @click="changeWeather">切换天气</button>

    </div>

    <script type="text/javascript">

        Vue.config.douctionTip = false

        const vm = new Vue({

            el:'#root',

            data:{

                isHot:true

            },

            computed:{

                info(){

                    return this.isHot ? '炎热':'凉爽'

                }

            },

            methods:{

                changeWeather(){

                    this.isHot = !this.isHot

                }

            },

       

        })

        vm.$watch('123',{

            handler(newValue,oldValue){

                console.log('isHot被修改该了',newValue,oldValue)

            }

        })

    </script>

</body>

</html>

  以上代码的效果为,正常执行,也不会报错,但不会监视到内容,所以也不会执行监视内部的代码

4、小结

  如果只要要监视的属性,可以直接在new Vue中写

  不确定要监视的属性,可以使用vm.$watch()方式

  多级监测属性时,不能使用简写方式,必须用引号引起来

  深度监测属性时,需要加一个配置:deep:true

  当需要使用immediatedeep等配置是,不能使用监测属性的简写形式