vue中的computed和watch

computed计算属性

先解读下官方文档,conputed的设计的初衷用于简答的运算,模板内不宜放入太多的逻辑,否则维护艰难。

    <div id="app">{{message.split("").reverse().join("")}}</div>
<script>

    var vm = new Vue({
        el:"#app",
        data:{
            message:"lxc"
        }
    })

上边代码,把字符串 "lxc" 逆反,在模板中写看似很酷,实则给维护增加困难。我们可以用计算属性:

    <div id="app">{{newMessage}}</div>
<script>

    var vm = new Vue({
        el:"#app",
        data:{
            message:"lxc"
        },
        computed:{
            newMessage(){
                return this.message.split("").reverse().join("")
            }
        }
    })

上边代码,模板是不是很清爽,而且逻辑很清晰,newMessage是计算出来的,它依赖data中的message,newMessage始终依赖于message,只要message改变,计算属性会检测到,newMessage也会发生改变。

大家可能会想我们把上边的例子写在方法中不是一样吗?

然而不同的是计算属性computed是基于他们的响应式依赖进行缓存的,只有依赖的值发生改变才会重新计算执行,也就是说,只有当message发生改变,newMessage才会重新计算,如果message没发生改变,多次访问newMessage,计算属性会返回之前的计算结果,而不必执行newMessage函数。

 

computed里边不是方法,而是属性,通过计算算出的一个属性,计算属性computed有几个特点:

        1、缓存数据;

        2、computed里边的属性不能再data中定义;

        3、不支持异步;

        4、默认get方法必须要有返回值。

        5、默认会调用getter方法,此方法的意思是:我们以上边为例,newMessage里边我们需要取到data中的message数据,对message进行一系列的操作,返回的是一个全新的值,这就是getter方法。其实上边也可以这样写:

computed:{
  newMessage:{
    get(){
       return this.message.split("").reverse().join("")
    },
    set(){
    
    }
  }
}

       6、computed里边还有一个setter方法,当自身改变影响其他依赖,都会调用setter方法,意思是:监听当前属性的变化,当属性发生改变时执行;此方法接收一个唯一的参数,参数意思是:更新的属性。。

举个例子:

<div id="app">
    <input type="checkbox" v-model="isAllSelect">全选<br>
    <div v-for="item in arr" :key="item.id">
        <input type="checkbox" v-model="item.state">{{item.text}}<br>
    </div>
</div>

<script>
    var vm = new Vue({
        el:"#app",
        data:{
            arr:[
                {text:"财富",state:false,id:"1"},
                {text:"青春",state:false,id:"2"}
            ]
        },
        computed:{
            isAllSelect:{
                get(){
                    return this.arr.every(ele=>ele.state)
                },
                set(newValue){
                    this.arr.forEach(ele=>ele.state = newValue)
                }
            }
        }
    })
</script>

上边例子是一个全选功能,大家可以复制代码运行;先下详细分析下:全选功能可以细分为2个小功能

     一是:全选框依赖复选框,当复选框全部勾选时,全选框会自动勾选,计算属性会调用computed中的getter方法,isAllSelect                  依赖数组中的state状态,every方法会判断每一个state状态,条件都符合才返回true,有一个不符合则返回false;

     二是:勾选全选框,复选框会跟随全选框变化而变化。也就是说,全选框自身变化,会影响复选框的状态,在计算属性会调                    用setter方法,参数newValue就是全选框的状态(true或false),把全选框状态赋值给下边的每一个复选框的状态,功                  能即可实现。。。

watch:侦听器

官方文档解释:当数据变化时执行异步时,用watch;无缓存功能。(主要应用场景:函数节流、防抖、ajax异步操作)

eg:(下边应用场景非常常用吗,输入框输入信息,watch监听到输入框值发生变化,从而向后台发球ajax请求!!!)

<div id="app">
    <input type="number" v-model.number="num" placeholder="请输入大于1的数字">
</div>
<script>
 var vm = new Vue({
    el:"#app",
    data:{
        num:"",
        timer:null
    },
    // watch里边的num函数,是查看num是否符合要求
    watch:{
        num(){
            if( this.num >= 2){
                this.debounce(this.success,2000);
            }else{
                this.debounce(this.error,2000)
            }
        }
    },
    methods:{
        // 防抖函数
        debounce(fn,delay){
            clearTimeout(this.timer);
            this.timer = setTimeout(fn,delay)
        },
        // 成功的回调
        success(){
            console.log(this)//这里的this指向vue实例,但是如果把回调函数写在setTimeout里边,this指向window,再次说明了:this的指向看函数在哪调用的,而不是看在哪执行的
            alert("成功")
        },
        // 失败的回调
        error(){
            alert("您输入的数字小于2了")
        }
    }
 })

</script>

实际开发中,实时校验输入框的内容,一般都是把内容发给后台,后台判断是否符合要求,返回给前台结果,这个过程是异步的了。上边代码,我们使用的定时器模拟了异步的过程;用watch监控num的数值,(computed计算属性无法执行异步操作)2秒钟后返回输入的数值是否符合要求;这里说下,里边用到了防抖函数,如果实时的去触发watch里边的监听函数,实际开发中对增加了服务器的负担,而且用户体验不好。。。

(补充)深度监听:

watch对于监测对象属性或方法的变化时,vue给到了一个深度监听的方法(此属性对性能开销比较大!!!因为每次修改对象的属性值watch都会监听到!!!):

watch:{
    object:{//对象
        handler(){//必写
            ··· ···
        },
        deep:true//必写
    }
}

watch监听一个对象object,对象里边是vue提供的一个必须写的方法handler方法,在此方法里边写逻辑;下边还需价一个属性deep:true。。。

eg:(监测对象属性,如果修改对象,把修改的对象存到内存中)

<div id="app">
<p>{{ text }}</p>
<button @click="click">click</button>//改变对象化中的属性按钮
</div>

<script>
var vm = new Vue({
	el: "#app",
	data: {
		text: [{ name: "lxc" }]
	},
	methods: {
		click() {
		    this.text[0].name = "hehe";
		}
	},
	watch: {
		text: {
		    handler() {
			    alert("1");
			    localStorage.setItem("content", JSON.stringify(this.text));//如果对象属性改变,会存到内存中去
		    },
		    deep: true
		}
	}
});
</script>

点击修改结果:

computed和watch的区别

1、computed不支持异步,watch支持异步;

2、computed对于监控多个数据的变化比watch写法上更优;(下边我们看下官网文档里的例子)

3、总之,计算属性computed能做的watch都能做,反之不行。

先用wtach来写下:用watch分别监听firstName和lastName的变化,发生改变会影响fullName

<div id="app">
    <h2>{{fullName}}</h2>
</div>

<script>
var vm = new Vue({
    el:"#app",
    data:{
        firstName:"吕",
        lastName:"星辰",
        fullName:"吕星辰"
    },
    watch:{
        firstName(val){
            this.fullName = val + this.lastName;
        },
        lastName(val){
            this.fullName = this.firstName + val;
        }
    }
})
</script>

在看下用computed写法:

<div id="app">
    <h2>{{fullName}}</h2>
</div>

<script>
 var vm = new Vue({
    el:"#app",
    data:{
        firstName:"吕",
        lastName:"星辰"
    },
    computed:{
        fullName(){
            return this.firstName + this.lastName;
        }
    }
 })
</script>

对比下是不是computed写法更好一些。。。

补充:

1、关于watch监听对象的问题,之前在群里看到有朋友在问题这样一个问题:为什么watch监听的对象中的handler函数2个参数输出结果都一样,当时也没在意,后来想了想决定自己打印下看看结果,结果还真是,都是输出的是改变之后的结果;

原因:出现以下问题的原因在于——只是修改了对象中的属性,对象的地址没改变,所以输出的值都是改变之后的;如果对象引用地址发生改变,两个参数就不一样了,一个是新值,一个是旧值。。。

<template>
    <div>
        <button @click="click">click</button>
    </div>
</template>

<script>
export default {
    name: "first",
    data(){
        return{
            ability:{
                name:"lxc",
                height:170
            }
        }
    },
    methods:{
        click(){
            this.ability.name = '鸡小西'
        }
    },
    watch:{
        ability:{
            handler(newValue,oldValue){
                console.log(newValue.name)
                console.log(oldValue.name)
            },
        deep:true
        }
    }
};

 

我们修改对象的引用地址,来看下:

methods:{
    click(){
        this.ability = {name:'鸡小西'}
    }
},
watch:{
   ability:{
      handler(newValue,oldValue){
         console.log(newValue.name)
         console.log(oldValue.name)
      },
      deep:true
    }
}

这回结果正常了:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值