计算属性及watch监听属性
-
计算属性
- 先看一个案例:动态渲染一个字母串,显示在页面时需要首字母大写,而从服务器请求回来的不一定会是首字母大写的情况,所以需要手动在前端作好处理。
<div id="box"> <!-- 将首字母大写,这里需要在页面中处理,这样的方式将业务逻辑写在了页面,会影响页面的可读性,这样的方式是不可取的。 --> {{myName.substr(0,1).toUpperCase() + myName.substr(1)}} </div> <script> var vm = new Vue({ el:"#box", data:{ myName:"tom" } }) </script>上面的案例,将js的业务处理放在了页面html中,违背了表现与行为分离的原则,页面变得臃肿,可读性降低,难以维护,这种现象我们称之为模板过重。要解决这样模板过重问题,可以使用vue中的计算属性computed
- computed:定义计算属性的地方
<div id="box"> <!-- 将首字母大写,这里需要在页面中处理,这样的方式将业务逻辑写在了页面,会影响页面的可读性,这样的方式是不可取的。 --> <!-- {{myName.substr(0,1).toUpperCase() + myName.substr(1)}} --> <!-- 使用计算属性, 他用计算属性,无需像调用方法一样,它本质上是已经是方法执行后的返回值。 --> {{ computedName }} </div> <script> var vm = new Vue({ el:"#box", data:{ myName:"tom" }, // 定义计算属性的地方 computed : { //定义了一个计算属性computedName //当myName发生改变,这里的计算属性也会同步的执行并更新结果 computedName(){ return this.myName.substr(0,1).toUpperCase() + this.myName.substr(1) } } }) </script> -
computed与methods的区别
computed:注重结果
1,逻辑计算,防止模板过重,有缓存 (计算属性在页面多次使用,方法不会重复调用,只有在模型数据发生更新时才会重新执行该函数 )
2,监听:依赖修改,get方法必须有return
methods(注重过程):
1,函数表达式的逻辑处理,没有缓存(页面使用几次,函数就会执行几次,没有缓存)
2,事件处理函数 ,return不是必需的
- 对比案例:
<div id="box"> <!-- 多次使用计算属性 --> {{ computedName }} {{ computedName }} {{ computedName }} <!-- 换行 --> <br> <!-- 多次调用方法 --> {{ comName() }} {{ comName() }} {{ comName() }} </div> <script> var vm = new Vue({ el:"#box", data:{ myName:"tom" }, methods:{ comName(){ //页面使用几次,函数就会执行几次,没有缓存 console.log("执行了方法") return this.myName.substr(0,1).toUpperCase() + this.myName.substr(1) } }, // 定义计算属性的地方 computed : { computedName(){ //计算属性在页面多次使用,方法不会重复调用,只有在模型数据发生更新时才会重新执行该函数 console.log("运行了计算属性") return this.myName.substr(0,1).toUpperCase() + this.myName.substr(1) } } }) </script>运行结果:

- 使用计算属性改造过滤搜索案例:
<div id="box">
<!-- v-model实现双向数据绑定 -->
<input type="text" v-model="myVal">
<ul>
<!-- 使用计算属性遍历数组 -->
<li v-for="item in computedData">
{{item}}
</li>
</ul>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
//绑定数据的模型
myVal:"",
list:["aaa","bbb","abc","bac","bbc","cbb","ccc"]
},
computed:{
//计算属性处理逻辑,返回更新后的数组
computedData(){
//根据数据myVal的实时变化,返回过滤后的数组
return this.list.filter(item=>item.includes(this.myVal));
}
}
})
</script>
-
计算属性的完整写法
-
计算属性可以被赋值,前提是要使用计算属性的完整写法
以上案例的计算属性写法均为简写,简写是无法给计算属性赋值的,否则会报错
-

下面我们来看看完整写法是怎样的:
案例:
<div id="box">
<!-- 使用计算属性的简写 -->
简写方式输出:{{ computedName }}
<br>
<!-- 使用计算属性的完整写法 -->
完整写法输出:{{ compName }}
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
myName:"tom"
},
// 定义计算属性的地方
computed : {
//这样的方式不是计算属性的完整写法,这是简写,简写方式无法赋值
computedName(){
return this.myName.substr(0,1).toUpperCase() + this.myName.substr(1)
},
//计算属性完整写法
compName : {
get(){
return this.myName.substr(0,1).toUpperCase() + this.myName.substr(1)
},
set(data){
this.myName = data;
}
}
}
})
</script>
修改计算属性结果:

-
计算属性get和set方法的使用场景
- 在购物车案例中使用,使用计算性属性实现判断是否全部选中的功能
<body> <div id="box"> <div class="all" v-if="list.length === 0">购物车空空如也</div> <template v-else> <!-- <div class="all"><input type="checkbox" v-model="isChecked" @change="allCheck()">全选|全不选</div> --> <!-- 使用计算属性来判断是否全部选中 --> <div class="all"><input type="checkbox" v-model="isCheckedComputed">全选|全不选</div> <ul> <li v-for="(item,index) in list" :key="item.id"> <div> <!-- <input type="checkbox" v-model="checkGroup" :value="item" @change="isAllCheck()"/> --> <!-- 使用计算属性无需再使用isAllCheck()方法了 --> <input type="checkbox" v-model="checkGroup" :value="item"/> </div> <div> <img :src="item.pic" alt=""> </div> <div> <div>名称:{{item.name}}</div> <div>价格:¥{{item.price}}</div> </div> <div> <button @click="item.number--" :disabled="item.number===1">-</button> <span>{{item.number}}</span> <button @click="item.number++" :disabled="item.number===item.limit">+</button> </div> <div> <button @click="deleteGood(index,item.id)">删除</button> </div> </li> </ul> <div class="all">总金额: {{totalPrice()}}</div> </template> </div> <script> var vm = new Vue({ el:"#box", data:{ isChecked:false, checkGroup:[], list:[.....] }, methods:{ totalPrice(){ var total = 0; this.checkGroup.forEach((ele)=>{ total += ele.price * ele.number; }) return total }, //删除商品 deleteGood(index,goodId){ //删除原商品 this.list.splice(index,1); //更新选中的商品 this.checkGroup = this.checkGroup.filter(ele => ele.id !== goodId) //删除单个商品时也要检测是否全部被选中 this.isAllCheck(); }, //全选全不选 // allCheck(){ // if(this.isChecked){ // this.checkGroup = this.list // }else{ // this.checkGroup = []; // } // }, //选择单个商品时,判断是否为全部选中 // isAllCheck(){ // if(this.checkGroup.length === this.list.length){ // this.isChecked = true; // }else{ // this.isChecked = false; // } // } }, //定义计算属性判断是否全部被选中 computed : { isCheckedComputed : { get(){ //选择后的商品个数与原商品个数相同,说明全部被选中,否则为没有全部被选中 return this.checkGroup.length === this.list.length; }, set(isChecked){ if(isChecked){ //全选按钮选中后,商品全部选中 this.checkGroup = this.list; }else{ this.checkGroup = [];//取消全选,选中的数组列表这空 } } } } }) </script> </body> -
watch监听属性
-
watch属性:监听,关注过程,无需return,无需调用。
监听指定数据状态,只要指定的数据发生改变,watch中所定义的对应属性会执行。
<div id="box"> <input type="text" v-model="myTest"> {{ myTest }} </div> <script> var vm = new Vue({ el:"#box", data:{ myTest:"" }, //监听 watch : { //定义要监听的属性 myTest(data){ console.log(data)//只要myTest的状态发生改变,这个程序就会执行,改变的状态值会以形参data的方式传递过来 } } }) </script>运行效果:
-

- watch实现购物车全选全不选功能
<div id="box">
<div class="all" v-if="list.length === 0">购物车空空如也</div>
<template v-else>
<!-- <div class="all"><input type="checkbox" v-model="isChecked" @change="allCheck()">全选|全不选</div> -->
<!-- 使用watch监听isChecked状态,无需再触发点击事件执行allCheck()方法 -->
<div class="all"><input type="checkbox" v-model="isChecked">全选|全不选</div>
<ul>
<li v-for="(item,index) in list" :key="item.id">
<div>
<input type="checkbox" v-model="checkGroup" :value="item" @change="isAllCheck()"/>
</div>
<div>
<img :src="item.pic" alt="">
</div>
<div>
<div>名称:{{item.name}}</div>
<div>价格:¥{{item.price}}</div>
</div>
<div>
<button @click="item.number--" :disabled="item.number===1">-</button>
<span>{{item.number}}</span>
<button @click="item.number++" :disabled="item.number===item.limit">+</button>
</div>
<div>
<button @click="deleteGood(index,item.id)">删除</button>
</div>
</li>
</ul>
<div class="all">总金额: {{totalPrice()}}</div>
</template>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
isChecked:false,
checkGroup:[],
list:[.....]
},
methods:{
totalPrice(){
var total = 0;
this.checkGroup.forEach((ele)=>{
total += ele.price * ele.number;
})
return total
},
//删除商品
deleteGood(index,goodId){
//删除原商品
this.list.splice(index,1);
//更新选中的商品
this.checkGroup = this.checkGroup.filter(ele => ele.id !== goodId)
//删除单个商品时也要检测是否全部被选中
this.isAllCheck();
},
//全选全不选
//使用了watch监听状态,allCheck()方法无需再使用
// allCheck(){
// if(this.isChecked){
// this.checkGroup = this.list
// }else{
// this.checkGroup = [];
// }
// },
//选择单个商品时,判断是否为全部选中
isAllCheck(){
if(this.checkGroup.length === this.list.length){
this.isChecked = true;
}else{
this.isChecked = false;
}
}
},
watch : {
//监听isChecked的状态
isChecked(val){
if(val){
this.checkGroup = this.list
}else{
//只有在上一次是全部选中的情况下,才全部取消选中
if(this.checkGroup.length === this.list.length)
this.checkGroup = [];
}
}
}
})
</script>
-
总结:
- data:定义数据模型的状态
- methods:
- 一般用于定义事件处理程序,或者函数表达试,不一定要使用return,是否使用return根据需求决定。没有缓存,如果多次调用表达式,每调用一次就会执行一次。
- computed:
- 注重结果
- 用于对一些逻辑的处理和计算,防止模板过重,有缓存,如果页面多次使用,不会重复运行。
- get方法必须使用return,set方法监听数据状态的改变,可以根据状态的改变对属性进行更新。
- watch:
- 监听指定数据模型状态,关注过程,无需return,无需调用,只要指定的数据状态发生改变,watch中所定义的对应属性会执行。
-
总结:
- data:定义数据模型的状态
- methods:
- 一般用于定义事件处理程序,或者函数表达试,不一定要使用return,是否使用return根据需求决定。没有缓存,如果多次调用表达式,每调用一次就会执行一次。
- computed:
- 注重结果
- 用于对一些逻辑的处理和计算,防止模板过重,有缓存,如果页面多次使用,不会重复运行。
- get方法必须使用return,set方法监听数据状态的改变,可以根据状态的改变对属性进行更新。
- watch:
- 监听指定数据模型状态,关注过程,无需return,无需调用,只要指定的数据状态发生改变,watch中所定义的对应属性会执行。
结论:需求的实现,具体使用以上哪个属性,不是固定的,主要是看需求,看场景,再找出最优方案。这需要对vue的执行原理有较深的理解,还需进一步学习。
本文详细介绍了Vue.js中的计算属性和watch监听属性,通过实例展示了它们在处理数据逻辑和模板过重问题上的应用。计算属性提供缓存机制,适用于多次使用的逻辑计算,而watch更关注数据变化的过程,适合监听数据状态。文中还通过购物车案例解释了计算属性get和set方法的使用场景,以及如何利用watch实现全选全不选功能。


被折叠的 条评论
为什么被折叠?



