最近做项目的时候遇到父子组件传参,需要子组件监听父组件传过来的值的变化以及对传过来值做一些处理这个过程踩了很多坑,记一次vue的watch监听与computed计算属性。
一.computed计算属性
1.特性
①是计算值
②就是简化tempalte里面{{}}计算和处理props或$emit的传值
③具有缓存性,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数
2.使用方法
1 data(){ 2 return{ 3 firstName: 'yinga', 4 lastName: 'xiang' 5 } 6 }, 7 computed: { 8 fullName:{ 9 get(){//回调函数 当需要读取当前属性值是执行,根据相关数据计算并返回当前属性的值 10 return this.firstName + ' ' + this.lastName 11 }, 12 //注意fullname不可在data里面定义, 13 //因为对应的computed作为计算属性定义fullName并返回对应的结果给这个变量,变量不可被重复定义和赋值 14 set(val){//监视当前属性值的变化,当属性值发生变化时执行,更新相关的属性数据 15 //val就是fullName的最新属性值 16 console.log(val) 17 const names = val.split(' '); 18 console.log(names) 19 this.firstName = names[0]; 20 this.lastName = names[1]; 21 } 22 } 23 }
3.游走于坑的周围
我们都知道父子组件传参是单向数据流,也就是说子组件中获取到的父组件的值是不能被修改的。如果非得对传过来的值进行一些处理可以在data中重新定义一个变量,然后把父组件传过来的值赋值给这个变量。那么问题来了,对于简单数据来说没问题,但是对于复杂类型数据,他在栈中存的指针,修改值就会影响到原数据。这个时候就需要深拷贝了。
关于这部分相关知识可见于-->js的深拷贝与浅拷贝。
但是但是但是我们的computed可以完美的解决这个问题。
1 computed:{ 2 fartherData(){ 3 return this.childData 4 } 5 }
注意:此时用computed时,如果是数组this.$set(arr,1,true)对应的值耶不更新,如果传入的值只是在data定义,并未在methods或生命周期钩子更改,直接改变也会报错。太难了,所以最稳妥的方法就是用一个变量接一下父组件传过来的这个值,然后再对这个值进行处理,简单数据类型直接浅拷贝就好,复杂数据类型深拷贝一下再处理。
二.watch监听属性
1.特性
①是观察的动作
②应用:监听props,$emit或本组件的值执行异步操作
③无缓存性,页面重新渲染时值不变化也会执行
2.简单数据类型使用方法
使用watch可以监听data中的数据变化, watch 中对应的 function 处理函数,该方法可以不用绑定事件
1 //这样写只适合简单数据类型的监听, 2 data(){ 3 return{ 4 firstName: 'yinga', 5 lastName: 'xiang', 6 fullName: 'yinga xiang' 7 } 8 }, 9 watch: { 10 firstName: function (val) { 11 this.fullName = val + ' ' + this.lastName 12 }, 13 lastName: function (val) { 14 this.fullName = this.firstName + ' ' + val 15 } 16 }
3.复杂数据类型监听
深度监听对应的函数名必须为handler,否则无效果,因为watcher里面对应的是对handler的调用
1 data(){ 2 return{ 3 yingaxiang:{ 4 first:0, 5 second:1 6 } 7 } 8 }, 9 watch:{ 10 secondChange:{ 11 handler(oldVal,newVal){ 12 console.log(oldVal) 13 console.log(newVal) 14 }, 15 deep:true 16 } 17 }, //打印发现oldVal和newVal值是一样的,所以深度监听虽然可以监听到对象的变化,但是无法监听到具体对象里面哪个属性的变化
①watch如果想要监听对象的单个属性的变化,必须用computed作为中间件转化,因为computed可以取到对应的属性值,这样computed与watch可以结合使用。
1 data(){ 2 return{ 3 'yingaxiang':{ 4 first:0, 5 second:1 6 } 7 } 8 }, 9 computed:{ 10 firstChange(){ 11 return this.yingaxiang.first 12 } 13 }, 14 watch:{ 15 firstChange(){ 16 console.log('first属性值变化了') 17 } 18 },
***这个方法也可以用在侦听父组件传给子组件的值,先通过计算属性得到引用类型的内部某个字段,再使用侦听器监听该字段的变化
②watch的deep深度监听属性
关于deep深度监听,就是说在对象中层层遍历,在监听对象上的每一个属性上都添加监听这样很损耗性能,但是对于我们组件化开发随着组件的销毁监听事件也销毁了,但是在组件外声明的监听事件需要使用unWatch方法注销,防止内存溢出。0.
1 watch: { 2 isShow:{ //深度监听,可监听到对象、数组的变化 3 handler (newV, oldV) { 4 // do something, 可使用this 5 console.log(newV,oldV) 6 }, 7 deep:true 8 } 9 },
③watch的newV,oldV使用
1 watch: { 2 $route.path == this.$route.path 3 '$route.path': function(newVal,oldVal){ 4 if(newVal === '/login'){ 5 console.log('欢迎进入login') 6 }else if(newVal === '/register'){ 7 console.log('欢迎进入register') 8 } 9 }