一、计算属性:
main.js:
var app = new Vue({
el: '#app',
data: {
math: 80,
physics: 90,
english: 30
},
computed: {
sum: function(){
return this.math + this.physics + this.english;
},
average: function(){
return Math.round((this.math + this.physics + this.english)/3);
}
}
});
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<table border="1">
<thead>
<td>学科</td>
<td>分数</td>
</thead>
<tr>
<td>数学</td>
<td><input type="text" v-model.number="math"/></td>
</tr>
<tr>
<td>物理</td>
<td><input type="text" v-model.number="physics"/></td>
</tr>
<tr>
<td>英语</td>
<td><input type="text" v-model.number="english"/></td>
</tr>
<tr>
<td>总分</td>
<td>{{sum}}</td>
</tr>
<tr>
<td>平均分</td>
<td>{{average}}</td>
</tr>
</table>
</div>
<script src="../lib/vue.js"></script>
<script src="./js/main.js"></script>
</body>
</html>
计算属性有两个特点:
1、只要计算属性中利用到的属性值发生改变它就会执行;
2、计算结果的值会缓存;
3、computed高级应用之:get、set
<p>{{fullName}}</p>
<p><button v-on:click="changeName">change</button></p>
<script>
var app = new Vue({
el: '#app',
data: {
firstName: "Samve",
lastName: "Duan"
},
computed: {
fullName: {
get: function(){
return this.firstName + " " + this.lastName;
},
set: function(newValue){//给fullName赋值为newValue时执行
this.firstName = newValue.split(" ")[0];
this.lastName = newValue.split(" ")[1];
}
}
},
methods: {
changeName: function(){
this.fullName = "xiao mi";//给计算属性fullName赋值
}
}
});
</script>
computed应用场景:
对于模板标签中任何复杂逻辑,你都应当使用计算属性;
你可以像绑定普通属性一样在模板中绑定计算属性。
二、侦听器:
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.css" rel="stylesheet"/>
</head>
<body>
<div id="app">
<input type="text" v-model="user.name"/>
<p>{{user.name}}</p>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
msg: 0,
user: {
id: 0,
name: 'Samve'
}
},
watch: {
msg: function(newMsg, oldMsg){
console.log('msg已被修改,newMsg:', newMsg, 'oldMsg:' + oldMsg);
},
user: {
handler: function(newValue, oldValue){
//handler默认执行函数,也可以去掉
console.log('user已经被修改,', newValue, oldValue);
},
deep: true//表示监视对象的属性变化,false则监视函数不执行,此时看不到newValue与oldValue的区别
//为了发现对象内部值的变化,可以在选项参数中指定deep:deep。注意:监听数组的变动不需要这么做
//主要用于监听属性是对象的属性变化
}
}
})
</script>
</body>
</html>
这其中有个问题,例如:
var vm=new Vue({
data:{
a:1,
b:{
c:1
}
},
watch:{
a(val, oldVal){//普通的watch监听
console.log("a: "+val, oldVal);
},
b:{//深度监听,可监听到对象、数组的变化
handler(val, oldVal){
console.log("b.c: "+val.c, oldVal.c);//但是这两个值打印出来却都是一样的
},
deep:true
}
}
})
vm.a=2
vm.b.c=2
a是一个普通的值,当a的值变化时会被监听到,b是一个对象,不能直接像a那么写,需要深度监听才能捕捉到,但是当我想去捕捉b对象中某一个值的变化时却发现,打印出来的两个值是一样的,如图:
这样就只能知道对象发生变化却不知道具体哪个值发生了变化,如果想监听对象某一个值得变化可以利用计算属性computed
var vm=new Vue({
data:{
b:{
c:1
}
},
watch:{
newValue(val, oldVal){
console.log("b.c: "+val, oldVal);
}
},
computed: {
newValue() {
return this.b.c
}
}
})
vm.b.c=2
用watch去监听computed计算过的值就可以直接知道是哪个对应的值发生了变化,结果如图:
三、计算属性的实际应用:
<script>
var vm = new Vue({
el: '#computed_props',
data: {
kilometers : 0,
meters:0
},
methods: {
},
computed :{
},
watch : {
kilometers:function(val) {
this.kilometers = val;
this.meters = val * 1000;
},
meters : function (val) {
this.kilometers = val/ 1000;
this.meters = val;
}
}
});
// $watch 是一个实例方法
vm.$watch('kilometers', function(newValue, oldValue){
// 这个回调将在 vm.kilometers 改变后调用
document.getElementById("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
})
</script>
四、计算属性与侦听器的比较:
计算属性顾名思义就是通过其他变量计算得来的另一个属性,fullName在它所依赖firstName,lastName这两个变量变化时重新计算自己的值。
另外,计算属性具有缓存。计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 lastName和firstName都没有发生改变,多次访问 fullName计算属性会立即返回之前的计算结果,而不必再次执行函数。
而侦听器watch是侦听一个特定的值,当该值变化时执行特定的函数。例如分页组件中,我们可以监听当前页码,当页码变化时执行对应的获取数据的函数。
①从属性名上,computed是计算属性,也就是依赖其它的属性计算所得出最后的值。watch是去监听一个值的变化,然后执行相对应的函数。
②从实现上,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算。watch在每次监听的值变化时,都会执行回调。其实从这一点来看,都是在依赖的值变化之后,去执行回调。很多功能本来就很多属性都可以用,只不过有更适合的。如果一个值依赖多个属性(多对一),用computed肯定是更加方便的。如果一个值变化后会引起一系列操作,或者一个值变化会引起一系列值的变化(一对多),用watch更加方便一些。
③watch的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作。computed通常就是简单的计算。
④watch和computed并没有哪个更底层,watch内部调用的是vm.$watch,它们的共同之处就是每个定义的属性都单独建立了一个Watcher对象。
总结:
1.如果一个数据依赖于其他数据,那么把这个数据设计为computed的
2.如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化:watch属性强调自身值得改变前后的动作,所以才有回调xxx(newVal,oldVal)
computed是用data已经申明的变量可以计算出来的另一个变量用来渲染页面比较合适方便,而watch适合监听某个data中的变量来操作一些逻辑行为比较合适,比如监听某个变量改变然后发起异步请求。