vue2的计算属性computed和侦听属性watch

一、计算属性computed

1、定义:需要使用的属性不存在,用通过已有的属性,计算得来一个新的属性。

2、原理:底层接住了defineProperty()方法提供的getter和setter;

        get函数调用时机:初次读取计算属性的时候执行一次;

                                      当依赖的数据发生改变的时候也会执行;

3、优势:与methods相比:

        1)computed具有缓存机制,多次调用只要依赖的数据不改变,直接读取缓存,效率更高;

        2)调试更方便,开发者工具中能够清晰的看到data和computed分开展示,清晰可见。

4、备注:

        1)计算属性最终也会出现在vm身上,模板中可以直接使用计算属性,像data中的数据一样。 

        2)如果计算属性要被修改,就必须写setter,用响应修改,且set中要引起计算属性依赖的属性发生变化。

// 通过  插值语法  实现姓名案例:
<div id="app">
  姓: <input type="text" v-model="firstName"> <br/><br/>
  名: <input type="text" v-model="lastName"> <br/><br/>
  全名: <span>{{firstName}}-{{lastName}}</span>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示

  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三'
    }
  })
</script>

// 通过  methods  实现姓名案例:
<div id="app">
  姓: <input type="text" v-model="firstName"> <br/><br/>
  名: <input type="text" v-model="lastName"> <br/><br/>
  全名: <span>{{fullName()}}</span> <br/><br/>// 执行一次
				<span>{{fullName()}}</span> <br/><br/>// 执行一次
				<span>{{fullName()}}</span> <br/><br/>// 执行一次
				<span>{{fullName()}}</span> <br/><br/>// 执行一次
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示

  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三'
    },
    methods:{
      fullName(){ // 调用多次
        console.log('fullname')
        // console.log(this) // this指向vm实例
        return this.firstName + "-" + this.lastName
      }
    }
  })
<script>
// 通过  computed 计算属性  实现姓名案例:
<div id="app">
  姓: <input type="text" v-model="firstName"> <br/><br/>
  名: <input type="text" v-model="lastName"> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>  // 执行一次,然后缓存
  全名: <span>{{fullName}}</span> <br/><br/>  // 直接读取缓存
  全名: <span>{{fullName}}</span> <br/><br/>  // 直接读取缓存
  全名: <span>{{fullName}}</span> <br/><br/>  // 直接读取缓存
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示

  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三'
    },
    computed:{  
      fullName:{  
				// 把computed中的fullName中的get中的返回值放在vm身上,所以模板中直接读取
        // get有什么作用??当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
        // get什么时候调用:1.初次读取fullName时,2.所依赖的数据发生变化时(firstName和lastName)
        get(){
          // console.log(this) // this指向vm ,不能使用箭头函数
          console.log('get被调用了')
          // return '小猪佩奇'
          return `${this.firstName}-${this.lastName}`
        },
         // set什么用??当有人修改fullName时,被调用
        //  set不一定必须写,一般计算属性只用于页面显示,就不用谢set了,一般情况只用get就可以,如果计算属性会被人修改,就必须写set(少数情况使用)
        set(value){
          console.log('set被调用')
          this.firstName = value.split("-")[0]
          this.lastName = value.split("-")[1]
        }
      }
    }
  })
</script>


//去掉注释后的代码:

<div id="app">
  姓: <input type="text" v-model="firstName"> <br/><br/>
  名: <input type="text" v-model="lastName"> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示

  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三'
    },
    computed:{  
      fullName:{ 
        get(){
          return `${this.firstName}-${this.lastName}`
        },
        set(value){
          this.firstName = value.split("-")[0]
          this.lastName = value.split("-")[1]
        }
      }
    }
  })

// 当只考虑读取计算属性,不考虑修改时,可以简写:
<div id="app">
  姓: <input type="text" v-model="firstName"> <br/><br/>
  名: <input type="text" v-model="lastName"> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示

  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三'
    },
    computed:{  
      fullName(){ 
        return `${this.firstName}-${this.lastName}`
      } 
    }
  })
</script>

二、侦听属性watch

1、监视属性特点:

        1)属性必须存在才能被监视。

        2)可以监视data中的属性,也可以监视计算属性;

        3)当监视的属性发生变化时,回调函数handler自动调用,执行相关代码,进行相关操作;

2、监视的两种方式:

        1)new Vue()时,直接在配置对象中配置watch配置项;

        2)通过vm.$watch监视;

3、深度监视:

        1)vue提供的watch默认不监视对象内部值的改变(只监视一层);

        2)配置deep:true可以开启深度监视,对对象内部进行深层监视(可监视多层);

        3)vue自身是可以监视对象内部值的变化的,但vue提供的watch默认不可以;

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

4、实例部分

// 通过差值语法方法,实现天气切换实例:
<div id="app">
  <h2>今天天气很{{isHot ? '炎热' : '凉爽'}}</h2>
//绑定事件的时候,@xxx = 'yyy', yyy可以写一些简单的语句
  <button @click="isHot = !isHot">切换天气</button>

</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
  let vm = new Vue({
    el: '#app',
    data: {
      isHot: true
    }
  })
</script>
// 通过计算属性方法,实现天气切换案例:
<div id="app">
  <h2>今天天气很{{info}}</h2>
  <button @click="changeWhether">切换天气</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
  let vm = new Vue({
    el: '#app',
    data: {
      isHot: true
    },
    computed: {
      info(){
        return this.isHot ? '炎热' : '凉爽'
      }
    },
    methods: {
      changeWhether(){
        this.isHot = !this.isHot;
      }
    }
  })
</script>
// 通过监听属性方法,实现天气切换案例:
<div id="app">
  <h2>今天天气很{{info}}</h2>
  <button @click="changeWhether">切换天气</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
  let vm = new Vue({
    el: '#app',
    data: {
      isHot: true,
      info: '炎热'
    },

    methods: {
      changeWhether(){
        this.isHot = !this.isHot;
      }
    },

	// 写法一:
    // watch: {
    //   isHot: {
    //     immediate: false, // 初始化是让handler调用一下;
    //     deep: false, // 深度侦听
    //     // handler什么时候调用?? 当isHot发生改变的时候;
    //     handler: function(newValue,oldValue){
    //       console.log('isHot被修改了',newValue,oldValue)
    //       this.info = this.isHot ? '炎热' : '凉爽'
    //     }
    //   }
    // }
  })

// 写法二:
  vm.$watch('isHot',{
    immediate: false, // 初始化是让handler调用一下;
    deep: false, // 深度侦听
    // handler什么时候调用?? 当isHot发生改变的时候;
    handler: function(newValue,oldValue){
      console.log('isHot被修改了',newValue,oldValue)
      this.info = this.isHot ? '炎热' : '凉爽'
    }
  })
</script>
// 深度监视
<body>
  <div id="app">
    <h2>{{number.a}}</h2>
    <button @click="number.a++">a++</button>
    <h2>{{number.b}}</h2>
    <button @click="number.b++">b++</button>
  </div>
  <script type="text/javascript" src="./vue.js"></script>
  <script>
    Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
    let vm = new Vue({
      el: '#app',
      data: {
        number:{
          a:1,
          b:2
        }
      },
      watch: {
        // 监视多级结构中某个属性的变化

        // 'number.a': {
        //   handler: function(newValue,oldValue){
        //     console.log('number.a被修改了',newValue,oldValue)
        //   }
        // },
        // 'number.b': {
        //   handler: function(newValue,oldValue){
        //     console.log('number.b被修改了',newValue,oldValue)
        //   }
        // }

        // 监视多级结构中所有属性的变化:深度监视deep:true
        number: {
          deep: true, // 深度侦听
          handler: function(newValue,oldValue){
            console.log('number被修改了')
          }
        }
      }
    })
  </script>
</body>

// 简写形式:
<div id="app">
  <h2>今天天气和{{info}}</h2>
  <button @click="changeWhether">切换天气</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
  let vm = new Vue({
    el: '#app',
    data: {
      isHot: true
    },
    computed: {
      info(){
        return this.isHot ? '炎热' : '凉爽'
      }
    },
    methods: {
      changeWhether(){
        this.isHot = !this.isHot;
      }
    },
    watch: {
      // 正常写法:
      // isHot: {
      //   // immediate:true,
      //   // deep: true, // 深度侦听
      //   handler: function(newValue,oldValue){
      //     console.log('number被修改了')
      //   }
      // }

      // 简写:
      // isHot(newValue,oldValue){
      //   console.log('number被修改了',newValue,oldValue)
      // }
    }
  })
  // 正常写法:
  vm.$watch('isHot',{
    // immediate:true,
    // deep: true, // 深度侦听
    // handler: function(newValue,oldValue){
    //   console.log('number被修改了')
    // }
  })

  // 简写:
  vm.$watch('isHot',function(newValue,oldValue){
    console.log('number被修改了',newValue,oldValue)
  })
</script>
// 姓名案例watch和computed对比
// 根据具体情况选择合适的方法
// watch属性
<div id="app">
  姓: <input type="text" v-model="firstName"><br><br>
  名: <input type="text" v-model="lastName"><br><br>
  全名: <span>{{fullName}}</span>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三',
      fullName: '张-三'
    },
    watch: {
      firstName(newValue){
        this.fullName = newValue + "-" + this.lastName;
      },
      lastName(newValue){
        this.fullName = this.firstName + "-" + newValue;
      }
    }
  })
</script>

// computed属性
<div id="app">
  姓: <input type="text" v-model="firstName"> <br/><br/>
  名: <input type="text" v-model="lastName"> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
  全名: <span>{{fullName}}</span> <br/><br/>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示

  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三'
    },
    computed:{  
      fullName(){ 
        return `${this.firstName}-${this.lastName}`
      } 
    }
  })
</script>



三、计算属性computed和侦听属性watch对比

 1、相同点

        1)都是根据依赖变化从而发生变化;

2、区别

        1)计算属性中,返回的是一个data中没有的值(新值)并且必须包含return;

        2)侦听器变化的值是data中存在的值,并且不包含return, 在侦听器中可以执行异步操作,并控制操作的频率,这些都是计算属性无法做到的

        3)computed能完成的功能,watch都可以完成;watch能完成的功能,computed不一定能完成;例如watch可以进行异步操作;

        4)虽然计算属性在大多数情况下更合适。Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。 当需要在数据变化时执行异步或开销较大的操作时,watch这个方式是最有用的。

        5)使用场景:

                watch适合处理的场景是:侦听一个数的变化,当该数据变化,来处理其他与之相关数据的变化(该数据影响别的多个数据)

                computed适合处理的场景是:获得一个值或者结果,该结果受其他的依赖的影响。(一个数据受多个数据影响)

3、两个重要的小原则:

        1) 所有被Vue管理的函数最好写成普通函数,这样this的指向才是vm 或者 组件实例对象;

        2) 所有不被Vue管理的函数(定时器的回调函数,ajax的回调函数,promise回调函数)最好写成箭头函数; 这样,this的指向才会指向vm或者组件实例对象;

<div id="app">
  姓: <input type="text" v-model="firstName"><br><br>
  名: <input type="text" v-model="lastName"><br><br>
  全名: <span>{{fullName}}</span>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
  Vue.config.productionTip = false; // 阻止Vue在启动时生成 生产提示
  let vm = new Vue({
    el: '#app',
    data: {
      firstName: '张',
      lastName: '三',
      fullName: '张-三'
    },
    watch: {
      firstName(newValue){
        setTimeout(()=>{ // 写成箭头函数,定时器是浏览器引擎的定时模块触发的,this指向window,箭头函数没有自己的this,会往外层找,找到的是vm,
          // 计算属性中如果加定时,在定时中return返回的数据不在vm身上,return跑到window身上了
					// 所以计算属性不能用定时等异步操作,watch不是返回,而是通this,直接改写vm身上的值,所以可以用于异步操作;
          this.fullName = newValue + "-" + this.lastName;
        },2000)
      },
      lastName(newValue){
        this.fullName = this.firstName + "-" + newValue;
      }
    }

  })
</script>


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值