Vue:计算属性

1、为何要使用计算属性

一、什么是计算属性

计算属性:能够理解为可以在里面写一些计算逻辑的属性。具备以下的做用:vue

  • 减小模板中的计算逻辑。
  • 数据缓存。当咱们的数据没有变化的时候,不会再次执行计算的过程。
  • 依赖固定的数据类型(响应式数据),不能是普通的传入的一个全局数据。

在数据量比较大的时候,计算属性能够帮助咱们提升性能,由于计算属性只会在数据变化的时候才会计算。git

在讲解计算属性以前先来看下面的一个例子:github

需求:外卖套餐A每份15元,客户点了3份,总价打八折,配送费5元,要求在界面显示总价,代码以下:数组

<template>
    <div>
        <div>您购买了{{info.name}}共{{info.count}}份</div>
        <h1>总价:{{info.count*info.price*info.sale+info.freight}}元</h1>
    </div>
</template>

<script> export default { name:'Test', data(){ return{ info:{ userId:1, price:15, name:'套餐A', count:3, sale:0.8, freight:5 } } } } </script>

界面运行效果:缓存

看了上面的例子,可能有人会问:使用这种方式已经实现了需求,那为何还要使用计算属性呢?咱们知道,vue中模板内的表达式很是便利,设计的初衷是用于简单运算的。若是在模板中放入太多的逻辑会让模板太重并且难以维护,看上面的代码:异步

<h1>总价:{{info.count*info.price*info.sale+info.freight}}元</h1>

 在这段代码中,模板不在是简单的声明式逻辑,而是复杂的逻辑计算,若是想要在多处引用总价的时候,就会难以维护。因此,对于任何复杂的逻辑,都应当使用计算属性。函数

看下面使用计算属性的例子:性能

<template>
    <div>
        <h1>计算属性</h1>
        <div>您购买了{{info.name}}共{{info.count}}份</div>
        <!--使用计算属性:和绑定普通属性同样-->
        <h1>总价:{{totalPrice}}元</h1>
    </div>
</template>

<script> export default { name:'ComputedDemo', data(){ return{ info:{ userId:1, price:15, name:'套餐A', count:3, sale:0.8, freight:5 } } }, computed:{ // 定义计算属性totalPrice
 totalPrice:function(){ return this.info.count*this.info.price*this.info.sale+this.info.freight } } } </script>

 界面显示效果:this

注意:计算属性是一个属性,不是方法,不能写在methods中,放在computed属性里面。spa

上面计算属性的写法也可使用ES6的写法:

// 使用ES6写法
totalPrice(){  return this.info.count*this.info.price*this.info.sale+this.info.freight }

2、计算属性和方法的区别

一、区别

上面的例子除了使用计算属性,还可使用方法实现:

<template>
    <div>
        <h1>计算属性</h1>
        <div>您购买了{{info.name}}共{{info.count}}份</div>
        <!--使用计算属性:和绑定普通属性同样-->
        <h1>使用计算属性获取总价:{{totalPrice}}元</h1>
        <h1>使用方法获取总价:{{getTotalPrice()}}元</h1>
    </div>
</template>

<script> export default { name:'ComputedDemo', data(){ return{ info:{ userId:1, price:15, name:'套餐A', count:3, sale:0.8, freight:5 } } }, computed:{ // 定义计算属性totalPrice
        // totalPrice:function(){
        // return this.info.count*this.info.price*this.info.sale+this.info.freight;
        // }
        // 使用ES6写法
 totalPrice(){ return this.info.count*this.info.price*this.info.sale+this.info.freight; } }, methods:{ getTotalPrice(){ return this.info.count*this.info.price*this.info.sale+this.info.freight; } } } </script>

 界面显示效果:

经过上面的例子能够看出:计算属性和方法实现的最终效果是相同的。那么计算属性和方法有什么区别呢?计算属性是基于它们的响应式依赖进行缓存的,只有在响应式依赖发生改变时才会从新求值。这就意味着只要响应式依赖没有发生改变,屡次访问计算属性会当即返回以前的计算结果,而没必要再次执行计算。相比之下,调用方法总会再次执行函数。总价计算属性和方法的区别以下:

  1. 计算属性在依赖发生改变时会自动改变,而方法在依赖发生改变时须要触发才会改变。
  2. 计算属性在依赖发生改变时才会从新计算,而方法在每次调用时都会执行。

看下面的例子:

<template>
    <div>
        <h1>计算属性</h1>
        <!-- <div>您购买了{{info.name}}共{{info.count}}份</div> -->
        <!-- 使用计算属性:和绑定普通属性同样 --> 您购买了<input type="text" v-model="info.name" /> 数量<input type="text" v-model="info.count" />
        
        <h1>使用计算属性获取总价:{{totalPrice}}元</h1>
        <button @click="getTotalPrice">计算属性</button>
        <h1>使用方法获取总价:{{data}}元</h1>
    </div>
</template>

<script> export default { name:'ComputedDemo', data(){ return{ info:{ userId:1, price:15, name:'套餐A', count:3, sale:0.8, freight:5 }, data:0 } }, computed:{ // 定义计算属性totalPrice
        // totalPrice:function(){
        // return this.info.count*this.info.price*this.info.sale+this.info.freight;
        // }
        // 使用ES6写法
 totalPrice(){ console.log('计算属性'); return this.info.count*this.info.price*this.info.sale+this.info.freight; } }, methods:{ getTotalPrice(){ console.log('方法'); this.data= this.info.count*this.info.price*this.info.sale+this.info.freight; } } } </script>

 当依赖发生改变时会屡次打印“计算属性”,而方法须要在点击按钮的时候才会发生改变。依赖不发生改变时点击按钮,也会打印“方法”。以下图所示:

二、计算属性使用场景

假如咱们有一个性能开销比较大的计算属性A,它须要遍历一个巨大的数组并作大量的计算,而后咱们可能有其余的计算属性依赖于计算属性A。若是不使用计算属性,那么将不可避免的屡次进行计算,会消耗很大的性能,这种状况下就须要使用计算属性。

3、修改计算属性的值

在上面的例子中都是使用的获取后的计算属性的值,那么如何修改计算属性的值呢?看下面的例子:

<template>
    <div>
        <h1>修改计算属性</h1>
        <h2>num:{{num}}</h2>
        <h2>计算属性num2:{{num2}}</h2>
        <button @click="change">改变计算属性的值</button>
    </div>
</template>

<script> export default { name:'ComputedDemo2', data(){ return{ num:100 } }, computed:{ num2(){ return this.num-10; } }, methods:{ change(){ this.num2=60; } } } </script>

 效果:

这时会发现直接修改计算属性的值报错了,由于不能直接修改计算属性的值,若是要修改计算属性的值,须要修改其依赖项的值,看下面的代码:

<template>
    <div>
        <h1>修改计算属性</h1>
        <h2>num:{{num}}</h2>
        <h2>计算属性num2:{{num2}}</h2>
        <button @click="change">改变计算属性的值</button>
    </div>
</template>

<script> import { get } from 'http'; export default { name:'ComputedDemo2', data(){ return{ num:100 } }, computed:{ num2:{ // 当计算属性要修改时先触发set方法
             // 读取当前计算属性中的值,get方法能够隐藏,默认进入的是get方法
 get:function(){ return this.num-10; }, set:function(val){ this.num=val; } } }, methods:{ change(){ // 计算属性不能直接修改
            this.num2=60; } } } </script>

修改前的效果:

修改后的效果:

总结

计算属性的值不能修改,若是要修改计算属性的值,要经过计算属性里面的set方法修改其依赖项的值才能修改计算属性的值。

4、监听属性

监听属性(watch)是用来监听data中的数据是否发生变化,通常是监听data中的某个属性。

  • 更加灵活、通用的API。
  • watch中能够执行任何逻辑,如函数节流,Ajax异步获取数据,甚至操做DOM。

一、监听普通属性

看下面的代码:

<template>
    <div>
        <h1>监听属性</h1> 姓名:<input type="text" v-model="userName"/>
        <h1>{{userName}}</h1> 年龄:<input type="text" v-model="age"/>
        <h1>{{age}}</h1>
    </div>
</template>

<script> export default { name:'watchDemo', data(){ return{ userName:"abc", age:23 } }, methods:{ change(){ } }, watch:{ // 监听userName的变化
        // 有两个参数,newValue表示变化后的值,oldValue表示变化前的值
 userName:function(newValue,oldValue){ console.log('修改前的值:'+oldValue); console.log('修改后的值:'+newValue); }, // 监听age的变化
 age:function(newValue,oldValue){ console.log('修改前的值:'+oldValue); console.log('修改后的值:'+newValue); } } } </script>

 界面效果:

二、监听属性和计算属性的区别

监听属性和计算属性的区别主要有下面几点:

  1. 计算属性性能更优。一个监听属性只能监听一个属性的变化,若是要同时监听多个,就要写多个监听属性,而计算属性能够同时监听多个数据的变化。
  2. 监听属性能够获取改变以前的属性值。
  3. 计算属性能作的,watch都能作,反之则不行。
  4. 能用计算属性尽可能用计算属性。

需求:userName或age改变的时候打印出当前的userName和age值。

用监听属性实现:

<template>
    <div>
        <h1>监听属性</h1> 姓名:<input type="text" v-model="userName"/>
        <h1>{{userName}}</h1> 年龄:<input type="text" v-model="age"/>
        <h1>{{age}}</h1>
        <!--打印userName和age的值-->
        <h1>{{info}}</h1>
    </div>
</template>

<script> export default { name:'watchDemo', data(){ return{ userName:"abc", age:23, info:'' } }, methods:{ change(){ } }, watch:{ // 监听userName的变化
        // 有两个参数,newValue表示变化后的值,oldValue表示变化前的值
 userName:function(newValue,oldValue){ // console.log('修改前的值:'+oldValue);
            // console.log('修改后的值:'+newValue);
            this.info= '个人姓名:'+ this.userName+',年龄:'+this.age; }, // 监听age的变化
 age:function(newValue,oldValue){ // console.log('修改前的值:'+oldValue);
            // console.log('修改后的值:'+newValue);
            this.info= '个人姓名:'+ this.userName+',年龄:'+this.age; } } } </script>

 若是要实现上述的需求,则须要对userName和age都进行监听,监听属性里面的代码都是重复的,若是有多个,那么就要写多个监听属性。在看计算属性:

<template>
    <div>
        <h1>监听属性</h1> 姓名:<input type="text" v-model="userName"/>
        <h1>{{userName}}</h1> 年龄:<input type="text" v-model="age"/>
        <h1>{{age}}</h1>
        <!--打印userName和age的值-->
        <!-- <h1>{{info}}</h1> -->
        <!--使用计算属性-->
        <h1>{{getUserInfo}}</h1>
    </div>
</template>

<script> export default { name:'watchDemo', data(){ return{ userName:"abc", age:23, info:'' } }, methods:{ change(){ } }, // watch:{
    // // 监听userName的变化
    // // 有两个参数,newValue表示变化后的值,oldValue表示变化前的值
    // userName:function(newValue,oldValue){
    // // console.log('修改前的值:'+oldValue);
    // // console.log('修改后的值:'+newValue);
    // this.info= '个人姓名:'+ this.userName+',年龄:'+this.age;
    // },
    // // 监听age的变化
    // age:function(newValue,oldValue){
    // // console.log('修改前的值:'+oldValue);
    // // console.log('修改后的值:'+newValue);
    // this.info= '个人姓名:'+ this.userName+',年龄:'+this.age;
    // }
    // }
 computed:{ getUserInfo(){ return '个人姓名:'+ this.userName+',年龄:'+this.age; } } } </script>

 若是使用计算属性则只须要写一次就能够实现上面的需求了。

三、监听复杂对象

上面的例子中是监听的普通属性,那么如何监听对象里面的属性呢?看下面的代码:

<template>
    <div>
        <h1>监听属性</h1> 姓名:<input type="text" v-model="userName"/>
        <h1>{{userName}}</h1> 年龄:<input type="text" v-model="age"/>
        <h1>{{age}}</h1>
        <!--打印userName和age的值-->
        <!-- <h1>{{info}}</h1> -->
        <!--使用计算属性-->
        <h1>{{getUserInfo}}</h1>
        <!--监听对象属性-->
        <h1>监听对象属性</h1> 姓名:<input type="text" v-model="obj.name"/>
        <h1>{{obj.name}}</h1>
    </div>
</template>

<script> export default { name:'watchDemo', data(){ return{ userName:"abc", age:23, info:'', // 对象
 obj:{ name:'123' } } }, methods:{ change(){ } }, watch:{ // 监听userName的变化
        // 有两个参数,newValue表示变化后的值,oldValue表示变化前的值
 userName:function(newValue,oldValue){ // console.log('修改前的值:'+oldValue);
            // console.log('修改后的值:'+newValue);
            this.info= '个人姓名:'+ this.userName+',年龄:'+this.age; }, // 监听age的变化
 age:function(newValue,oldValue){ // console.log('修改前的值:'+oldValue);
            // console.log('修改后的值:'+newValue);
            this.info= '个人姓名:'+ this.userName+',年龄:'+this.age; }, // 监听对象中属性的变化
        'obj.name':function(newValue,oldValue){ console.log('修改前的值:'+oldValue); console.log('修改后的值:'+newValue); } }, computed:{ getUserInfo(){ return '个人姓名:'+ this.userName+',年龄:'+this.age; } } } </script>

 效果:

能不能执行监听对象呢?答案是能够的,看下面代码:

<template>
    <div>
        <h1>监听属性</h1> 姓名:<input type="text" v-model="userName"/>
        <h1>{{userName}}</h1> 年龄:<input type="text" v-model="age"/>
        <h1>{{age}}</h1>
        <!--打印userName和age的值-->
        <!-- <h1>{{info}}</h1> -->
        <!--使用计算属性-->
        <h1>{{getUserInfo}}</h1>
        <!--监听对象属性-->
        <h1>监听对象属性</h1> 姓名:<input type="text" v-model="obj.name"/>
        <h1>{{obj.name}}</h1>
        <!--监听对象-->
        <h1>监听对象</h1> 姓名:<input type="text" v-model="obj.name"/>
        <h1>{{obj.name}}</h1>
    </div>
</template>

<script> export default { name:'watchDemo', data(){ return{ userName:"abc", age:23, info:'', // 对象
 obj:{ name:'123' } } }, methods:{ change(){ } }, watch:{ // 监听userName的变化
        // 有两个参数,newValue表示变化后的值,oldValue表示变化前的值
 userName:function(newValue,oldValue){ // console.log('修改前的值:'+oldValue);
            // console.log('修改后的值:'+newValue);
            this.info= '个人姓名:'+ this.userName+',年龄:'+this.age; }, // 监听age的变化
 age:function(newValue,oldValue){ // console.log('修改前的值:'+oldValue);
            // console.log('修改后的值:'+newValue);
            this.info= '个人姓名:'+ this.userName+',年龄:'+this.age; }, // 监听对象中属性的变化
        // 'obj.name':function(newValue,oldValue){
        // console.log('修改前的值:'+oldValue);
        // console.log('修改后的值:'+newValue);
        // }
        // 直接监听对象
 obj:{ // handler表示默认执行的函数
 handler(newValue,oldValue){ console.log('修改前的值:') console.log(oldValue); console.log('修改后的值:'); console.log(newValue); }, // 表示深度监听 
            // true:表示handler函数会执行
            // false:表示handler函数不会执行
 deep:true } }, computed:{ getUserInfo(){ return '个人姓名:'+ this.userName+',年龄:'+this.age; } } } </script>

 效果:

 GitHub代码地址:https://github.com/JiangXiaoLiang1988/computed.git

相关文章
相关标签/搜索