Vue的监视属性-watch

文章目录

  • 监视属性
    • 引例
    • 普通实现
    • 使用监视属性watch检测天气变化
      • 第一种配置方法,设置watch属性
      • 使用vm对象进行监视
      • 两种监视的使用情况
  • 深度监视
    • 监视多级结构中某个属性的变化(引例,不是深度监视)
    • 监视多级结构中所有属性的变化(——是深度监视)
      • 深度监视小结
  • 监视的简写
    • watch属性监视的简写
    • vm对象监视的简写
  • 计算属性和监视属性的对比
    • 代码量对比
    • 异步回调对比
    • 对比小结
  • 两个重要的原则:

监视属性

引例

实现效果:点击切换天气按钮,天气可以在炎热和凉爽之间切换。
Vue的监视属性-watch_第1张图片

普通实现

实现:

DOCTYPE html>
<html lang="en">
<head>
    <title>Documenttitle>
    <script type="text/javascript" src="../js/vue.js">script>
head>
<body>
    <div id="root">
        <h2>今天天气很{{info}}h2>
        <button @click="changeWeather">切换天气button>
    div>
    <script type='text/javascript'>
    Vue.config.productionTip = false;
      new Vue({
          el:'#root',
          data: {
            isHot:true
          },
          computed:{
            info(){
               return this.isHot?"炎热":"凉爽"
            }
          },
          methods: {
            changeWeather(){
                this.isHot = !this.isHot
            }
          },
      })
    script>
body>
html>

也可以不使用函数,直接在 @click中对变量进行处理
即绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句,但是如果语句比较复杂就不适合这样写了

DOCTYPE html>
<html lang="en">
<head>
    <title>Documenttitle>
    <script type="text/javascript" src="../js/vue.js">script>
head>
<body>
    <div id="root">
        <h2>今天天气很{{info}}h2>
        <button @click="isHot = !isHot">切换天气button>
    div>
    <script type='text/javascript'>
    Vue.config.productionTip = false;
      new Vue({
          el:'#root',
          data: {
            isHot:true
          },
          computed:{
            info(){
               return this.isHot?"炎热":"凉爽"
            }
          },
        //   methods: {
        //     changeWeather(){
        //         this.isHot = !this.isHot
        //     }
        //   },
      })
    script>
body>
html>

使用监视属性watch检测天气变化

监视的特点:

  • 当被监视的属性变化时,回调函数自动调用,进行相关操作
  • 监视的属性必须存在,才能进行监视
  • 有两种监视方法

第一种配置方法,设置watch属性

使用watch监视需要设置配置属性watch
格式如下:

watch:{
   要监视的属性(可以是vue的普通属性也可以是计算属性):{
       immediate:true,//初始化时执行一次handler
       // 要监视的属性的值发生了改变就执行handler函数
       //newValue代表修改后的值,oldValue代表修改前的值
       handler(newValue,oldValue){
           console.log("修改了",newValue,oldValue)
       }
   }
 }

代码如下:

DOCTYPE html>
<html lang="en">
<head>
    <title>Documenttitle>
    <script type="text/javascript" src="../js/vue.js">script>
head>
<body>
    <div id="root">
        <h2>今天天气很{{info}}h2>
        <button @click="changeWeather">切换天气button>
    div>
    <script type='text/javascript'>
    Vue.config.productionTip = 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函数
                handler(newValue,oldValue){
                    console.log("isHot被修改了",newValue,oldValue)
                }
            },
            info:{
                immediate:true,//初始化时执行一次handler
                // isHot的值发生了改变就执行handler函数
                handler(newValue,oldValue){
                    console.log("info被修改了",newValue,oldValue)
                }
            },

          }
      })
    script>
body>
html>

输出:

Vue的监视属性-watch_第2张图片

使用vm对象进行监视

格式

        vm.$watch('要监视的属性',{
            immediate:true,//初始化时执行一次handler
            // 要监视的属性t的值发生了改变就执行handler函数
            handler(newValue,oldValue){
                console.log("监视的属性修改了",newValue,oldValue)
            }
        })

eg:

DOCTYPE html>
<html lang="en">
  <head>
    <title>Documenttitle>
    <script type="text/javascript" src="../js/vue.js">script>
  head>
  <body>
    <div id="root">
      <h2>今天天气很{{info}}h2>
      <button @click="changeWeather">切换天气button>
    div>
    <script type="text/javascript">
      Vue.config.productionTip = false;
      const vm = new Vue({
        el: "#root",
        data: {
          isHot: true,
        },
        computed: {
          info() {
            return this.isHot ? "炎热" : "凉爽";
          },
        },
        methods: {
          changeWeather() {
            this.isHot = !this.isHot;
          },
        },
      });

      vm.$watch("isHot", {
        immediate: true, //初始化时执行一次handler
        // isHot的值发生了改变就执行handler函数
        handler(newValue, oldValue) {
          console.log("isHot被修改了", newValue, oldValue);
        },
      });
      vm.$watch("info", {
        immediate: true, //初始化时执行一次handler
        // isHot的值发生了改变就执行handler函数
        handler(newValue, oldValue) {
          console.log("info被修改了", newValue, oldValue);
        },
      });
    script>
  body>
html>

两种监视的使用情况

  • watch监视适用于已经确定好检测对象的情况
  • vm.$watch监视适用于检测对象不确定的情况

深度监视

监视多级结构中某个属性的变化(引例,不是深度监视)

即如果一个属性对象,我们想要监视对象中某一个属性的变化,这时候就用到深度监视。
因为需要使用.获取对象属性,所以这里监视的对象需要用引号引起来。
格式:

watch:{
   'numbers.a':{
       handler(newValue,oldValue){
           console.log("isHot被修改了",newValue,oldValue)
       }
   }
 }

实际上配置对象的属性名本来就是要加引号的,不加引号只是简写形式,如果出现了.属性这类情况引号就不可以省略了。

eg:

DOCTYPE html>
<html lang="en">
<head>
    <title>Documenttitle>
    <script type="text/javascript" src="../js/vue.js">script>
head>
<body>
    <div id="root">
        <h3>a的值是{{number.a}}h3>
        <button @click="number.a++">点我a加1button>
    div>
    <script type='text/javascript'>
    Vue.config.productionTip = false;
    const mv = new Vue({
          el:'#root',
          data: {
            number:{
                a:1,
                b:1
            }
          },
          watch:{
            'number.a':{
                handler(newValue,oldValue){
                    console.log("a被修改了",newValue,oldValue)
                }
            }
          }
  
      })

    script>
body>
html>

Vue的监视属性-watch_第3张图片

监视多级结构中所有属性的变化(——是深度监视)

当我们想要监视number中所有属性的变化,即number中任何一个属性发生了改变就进行监视输出。

  • 直接监视number
  'number':{
      handler(newValue,oldValue){
          console.log("number被修改了",newValue,oldValue)
      }
  }

不可行,因为number监视的是number的值,而number的值是它所指向的对象的地址,所以他监视的不是属性值a和b的变化。

  • 这时候就需要用到深度检测了
    是需要设置deep:true,就可以使number监视的是number的对象的值,即属性值a和b的变化。
'number':{
      deep:true,
      handler(newValue,oldValue){
          console.log("number被修改了",newValue,oldValue)
      }
  }

eg:

DOCTYPE html>
<html lang="en">
<head>
    <title>Documenttitle>
    <script type="text/javascript" src="../js/vue.js">script>
head>
<body>
    <div id="root">
        <h3>a的值是{{number.a}}h3>
        <button @click="number.a++">点我a加1button>
    div>
    <script type='text/javascript'>
    Vue.config.productionTip = false;
    const mv = new Vue({
          el:'#root',
          data: {
            number:{
                a:1,
                b:1
            }
          },
          watch:{
            'number.a':{
                handler(newValue,oldValue){
                    console.log("a被修改了",newValue,oldValue)
                }
            },
            'number':{
                deep:true,
                handler(newValue,oldValue){
                    console.log("number被修改了",newValue,oldValue)
                }
            }
          }
  
      })

    script>
body>
html>

Vue的监视属性-watch_第4张图片

深度监视小结

深度监视:
(1)Vue中的watch默认不监测对象内部值的改变(一层)。
(2)配置deep:true可以监测对象内部值改变(多层)。

注意:
(1)vue自身可以监测对像内部值的改变,但Vue提供的watch默认不可以!
(2)使用watch时根据数据的具体结构,决定是否采用深度监视。

监视的简写

当监视的对象只有 handler配置时就可以开启简写模式

watch属性监视的简写

 watch:{
   isHot:{
       handler(newValue,oldValue){
           console.log("isHot被修改了",newValue,oldValue)
       }
   },
 }

可以简写为

 watch:{
   isHot(newValue,oldValue){
       console.log("isHot被修改了",newValue,oldValue)
   },
 }

vm对象监视的简写

      vm.$watch("isHot", {
        handler(newValue, oldValue) {
          console.log("isHot被修改了", newValue, oldValue);
        },
      });

可简写为

      vm.$watch("isHot", function(newValue, oldValue){
         console.log("isHot被修改了", newValue, oldValue);
      })

计算属性和监视属性的对比

代码量对比

实现效果:
Vue的监视属性-watch_第5张图片
计算属性实现

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>姓名案例title>
    <script type="text/javascript" src="../js/vue.js">script>
  head>
  <body>
    <div id="root">
      姓:<input type="text" v-model="firstname"><br/>
      名:<input type="text" v-model="lastname"><br/>
      姓名:<span>{{fullName}}span>
    div>
    <script>
      Vue.config.productionTip = false;
      const vm = new Vue({
          el:'#root',
        //   在vue中会将data中的值看作属性
          data: {
            firstname:'张',
            lastname:'三'
          },
        //   计算属性
        // 计算属性:将写完的属性进行加工计算生成一个全新的属性
          computed:{
            fullName:{
                // get作用:有人读取fullname时会调用get,且返回值作为fullname的值
                get(){
                    // 此处的this是vm
                    return this.firstname +"-"+this.lastname
                },
            }
          }
          
      })

    script>
  body>
html>

监视属性实现:

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>姓名案例title>
    <script type="text/javascript" src="../js/vue.js">script>
  head>
  <body>
    <div id="root">
      姓:<input type="text" v-model="firstname" /><br />
      名:<input type="text" v-model="lastname" /><br />
      姓名:<span>{{fullName}}span>
    div>
    <script>
      Vue.config.productionTip = false;
      const vm = new Vue({
        el: "#root",
        //   在vue中会将data中的值看作属性
        data: {
          firstname: "张",
          lastname: "三",
          fullName: "张-三",
        },
        watch: {
          // 简写
          firstname(newValue, oldValue) {
            this.fullName = newValue + "-" + this.lastname;
          },
          lastname(newValue, oldValue) {
            this.fullName = newValue + "-" + this.lastname;
          },
        },
      });
    script>
  body>
html>

在这个案例中,计算属性更方便简单一些。

异步回调对比

需求,当姓改变的时候,一秒后名字再改变:

  • 计算属性无法实现异步操作
computed:{
     fullName:{
         get(){
             setTimeout(() => {
               // 调用箭头函数之后,返回值就是箭头函数的返回值了,而fullName就没有返回值了,所以会出错
               return this.firstname +"-"+this.lastname
             }, 1000);  
         },
     }
   }

输出结果:
Vue的监视属性-watch_第6张图片

  • watch可以实现异步操作
watch: {
   // 简写
   firstname(newValue, oldValue) {
     setTimeout(() => {
       this.fullName = newValue + "-" + this.lastname;
     }, 1000);
     
   },
   lastname(newValue, oldValue) {
     this.fullName = newValue + "-" + this.lastname;
   },
 },

问题 : 如果setTimeout中写的不是箭头函数,而是普通函数那么this是谁?

  • 答案是Windows,因为是windows为setTimeout设置的函数,
    问题 :为什么setTimeout中写的是箭头函数,而this是vm?
  • 因为箭头函数没有this他就会向外找this,外层的this是vm

对比小结

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

两个重要的原则:

  1. 被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
  2. 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

目的都是使this指向vue。

你可能感兴趣的:(vue2+vue3,vue.js,前端,javascript)