Vue的computed和watch的细节全面分析

3,428 阅读3分钟
原文链接: segmentfault.com

定义

1.computed是一个计算属性,类似于过滤器,对绑定到view的数据进行处理,并监听变化,如下对应的computedDataRes就是接受返回值,并监听变化,变化可以执行方法computedMethod,

  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }

fullName不可在data里面定义,如果定义会报错,因为对应的computed作为计算属性定义fullName并返回对应的结果给这个变量,变量不可被重复定义和赋值

图片描述

2.watch是一个观察的动作

  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
     firstName: function (val) {
     this.fullName = val + ' ' + this.lastName
  },
  lastName: function (val) {
     this.fullName = this.firstName + ' ' + val
   }
   }
   

watch的使用

watch监听简单数据类型

data(){
      return{
        'first':2
      }
    },
    watch:{
      first(){
        console.log(this.first)
      }
    },

watch监听复杂数据类型

1.watch监听复杂数据类型需用深度监听

data(){
      return{
        'first':{
          second:0
        }
      }
    },
    watch:{
      secondChange:{
        handler(oldVal,newVal){
          console.log(oldVal)
          console.log(newVal)
        },
        deep:true
      }
    },

2.console.log打印的结果,发现oldVal和newVal值是一样的,所以深度监听虽然可以监听到对象的变化,但是无法监听到具体对象里面那个属性的变化

图片描述

3.深度监听对应的函数名必须为handler,否则无效果,因为watcher里面对应的是对handler的调用

watch监听对象单个属性

watch如果想要监听对象的单个属性的变化,必须用computed作为中间件转化,因为computed可以取到对应的属性值

data(){
      return{
        'first':{
          second:0
        }
      }
    },
    computed:{
      secondChange(){
        return this.first.second
      }
    },
    watch:{
      secondChange(){
        console.log('second属性值变化了')
      }
    },
    

应用一(本组件计算和监听)

应用二(修改或监听其他组件传入的值)

props传入的值

1.情况一:作为局部变量来使用A.传入的值想作为局部变量来使用,直接使用会

props:['listShop'],
    data(){
      return{}
    },
    created(){
      this.listShop=30
}

报错

图片描述

这个错误是说的避免直接修改父组件传入的值,因为会改变父组件的值,贴上官网介绍

B.简单数据类型解决方案:所以可以在data中重新定义一个变量,改变指向,但是也只是针对简单数据类型,因为复杂数据类型栈存贮的是指针,

props:['listShop'],
    data(){
      return{
        listShopChild:this.listShop
      }
    },
    created(){
      this.listShopChild=30
    }
    

这样就可以愉快的更改传入的简单数据类型的数据啦!不会有任何报错,也不会影响父组件!

C.复杂数据类型解决方案:
复杂数据类型在栈中存贮的是指针,所以赋值给新的变量也会改变原始的变量值.那么应该咋整呢?
<1.>可以手动深度克隆一个复杂的数据出来,循环或者递归都行

数组深度克隆:

var x = [1,2,3];
var y = [];
for (var i = 0; i < x.length; i++) {
    y[i]=x[i];
}
console.log(y);  //[1,2,3]
y.push(4);
console.log(y);  //[1,2,3,4]
console.log(x);  //[1,2,3]

对象深度克隆:

var x = {a:1,b:2};
var y = {};
for(var i in x){
    y[i] = x[i];
}
console.log(y);  //Object {a: 1, b: 2}
y.c = 3;
console.log(y);  //Object {a: 1, b: 2, c: 3}
console.log(x);  //Object {a: 1, b: 2}

函数深度克隆

var x = function(){console.log(1);};
var y = x;
y = function(){console.log(2);};
x();  //1
y();  //2

为什么函数可以直接赋值克隆?由于函数对象克隆之后的对象会单独复制一次并存储实际数据,因此并不会影响克隆之前的对象。所以采用简单的复制“=”即可完成克隆。

<2.>Object.assign
只会对只是一级属性复制,比浅拷贝多深拷贝了一层而已,所以还是无法达到深度克隆的目的.
详请请戳

<3.>强大的JSON.stringify和JSON.parse

const obj1 = JSON.parse(JSON.stringify(obj));

这是ES5新出来的API,先将对象转化为字符串,就是简单数据类型赋值,再用JSON.parse转化

2.情况二:处理后再使用可以先用局部变量接收,再修改

检测子传父的值

分为简单数据类型和复杂数据类型检测,检测方法如上watch的使用

应用三(监听vuex的state值变化)

computed:{
    stateDemo(){
        return this.$store.state.demoState;
    }
}
watch:{
    stateDemo(){
        console.log('vuex变化啦')
    }
}

computed和watch的原理分析

很开心小伙伴们能看到这里,接下来给大家简单罗列下他们的原理!

computed的原理

参照下面这个URL:segmentfault.com/a/11...

watch的原理

分为三个过程:实例化Vue、调用$watch方法、属性变化,触发回调
参照这两个URL:www.cnblogs.com/Clare...
segmentfault.com/a/11...

大家如果发现有什么错误,欢迎指正,共同交流。如果觉得篇文章真的对你有点作用。谢谢亲们能看完!