<div id="app">
{{text}}
<br>
<!--将123,456,789变成789,456,123-->
<!--这种写法太臃肿了,这里的表达式包含 3 个操作,并不是很清晰,所以在遇到复杂的逻辑时应该使用 计算属性-->
{{text.split(',').reverse().join(',')}}
<br>
<!--使用计算属性后的代码-->
{{reserve}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
text: '123,456,789'
},
computed: {
reserve(){
return this.text.split(',').reverse().join(',')
}
}
})
</script>
所有的计算属性都以函数的形式写在 Vue 实例内的computed 选项内,最终返回计算后的结果。
3.1. 计算属性用法
在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。除了上例简单的用法, 计算属性还可以依赖多个 Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新 。
实例 :展示两个购物车的物品总价
<div id="app">
{{priceSum}} /*44400-------我是app2里面的内容*/
</div>
<script>
//需求:计算购物车中所有商品的价格
var app2 = new Vue({
el: '#aaa',
data: {
msg: '我是app2里面的内容'
}
})
var app = new Vue({
el: '#app',
data: {
//当package1和package2里面的数据改变,计算属性里的总价格也会同步改变
package1: [
{name: 'iphone',price: 3000,count:2},
{name: 'ipad',price: 4000,count:3}
],
package2: [
{name: 'clother',price: 600,count:4},
{name: 'computer',price: 12000,count:2},
]
},
computed: {
priceSum(){
var price1=0;
var price2 = 0;
for(var i =0;i<this.package1.length;i++){
price1 += this.package1[i].price* this.package1[i].count
}
for(var i =0;i<this.package2.length;i++){
price2 += this.package2[i].price* this.package2[i].count
}
return price1 + price2 +'-------'+app2.msg//这里可以通过计算属性访问app2实例里的内容
//说明了计算属性还可以依赖多个 Vue 实例的数据
}
}
})
</script>
3.1.1. getter和setter
每一个计算属性都包含-个 getter 和一个 setter,我们上面的两个示例都是计算属性的默认用法 ,只是利用了 getter 来读取。在你需要时,也可以提供一个 setter 函数 , 当手动修改计算属性的值就像修改一个普通数据那样时,就会触发 setter函数,执行一些自定义的操作
<div id="app">
{{showName}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
firstName: 'wang',
lastName: 'lifa'
},
computed: {
//如果直接computed里的属性后面的值是function,那么默认就是调用了computed的getter方法
//showName:function(){
// return this.firstName + this.lastName
//}
//等价于
showName: {
get:function(){
return this.firstName + this.lastName
}
}
}
})
</script>
setter的使用(直接this.computed里的对象名=’你新的值’,也就是你给它赋值的时候直接会调用set方法)
showName: {
get:function(){
return this.firstName + ' ' + this.lastName
},
set:function(newName){//set方法调用:直接this.showName= 'Wei,linlin'
//newName是你设置的数据,也就是'Wei,linlin'
var newName = newName.split(',')
this.firstName = newName[0]
this.lastName = newName[1]
}
}
上面的代码当在页面上写this.showName=’Wei,linlin’的时候,页面上的名字就会从wanglifa变成weilinlin了
3.3. 计算属性缓存
小实例:
<div id="app">
{{reserve}} <br>
计算属性: <br>
{{now}} <br>
<br>
通过methods拿到的时间戳(方法必须加括号): <br>
{{this.now1()}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
text: '123,456,789',
msg:'222'
},
computed: {
reserve: function(){
return this.text.split(',').reverse().join(',')
},
now: function(){
return Date.now()
}
},
methods: {
now1:function(){
return Date.now()
}
}
})
</script>
上面代码运行后页面显示如下:
但是当修改了text的值后,
通过methods方法获取的时间戳的值变了,而计算属性获取的一直没变。
因为上面页面中的
{{reserve}}
里有对text值的操作,也就是页面中挂载了text,所以当text的值发生改变,页面会重新渲染,而methods
里的方法只要页面重新渲染,就会重新执行,所以上面的时间值更新了。而msg属性页面中并没用到,所以即使它变了,页面也不会去渲染,故methods里的方法没有执行----->>总结:页面中的方法:如果是调用方法,只要页面重新渲染。方法就会重新执行,不需要渲染,则不需要重新执行。
上面代码因为计算属性里的时间戳没有依赖于任何属性,所以不管页面怎么渲染都不会发生变化,而最上面的{{reserve}}里的值,因为是依赖与text属性的,所以当text属性变化,它也会跟着变化----->>>总结:计算属性,不管渲染不渲染,只要计算属性依赖的数据未发生变化,就永远不变。
调用 methods 里的方法也可以与计算属性起到同样的作用。
结论: 没有使用计算属性,在 methods 里定义了一个方法实现了相同的效果,甚至该方法还可以接受参数,使用起来更灵活。既然使用 methods 就可以实现,那么为什么还需要计算属性呢?
原因就是:计算属性是基于它的依赖缓存的。 一个计算属性所依赖的数据发生变化时,它才会重新取值,所以text 只要不改变,计算属性也就不更新。
何时使用: -----------使用计算属性还是 methods 取决于你是否需要缓存,当遍历大数组和做大量计算时,应当使用 计算属性,除非你不希望得到缓存。
data和computed的区别
data函数只会在组件创建的时候运行一次,之后data里数据的改变只是在各个钩子里变化,而computed是只要依赖的数据变了,它就会运行,就会重新改变
watch
一个对象,键是需要观察的表达式,值是对应回调函数(函数里的形参第一个是新值,第二个是旧值)。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。也就是只要你监听的属性改变时,它就会调用它里面的方法
var vm = new Vue({
data: {
a: 1,
b: 2,
c: 3,
d: 4,
e: {
f: {
g: 5
}
}
},
watch: {
//当a的值变化时,就会调用这个函数
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
// 方法名
b: 'someMethod',
// 深度 watcher
e: {
//handler这个属性时自带的回调函数名
handler: function (val, oldVal) { /* ... */ },
//加上这句后,e这个对象里的任何一个属性值变化,都会执行这个函数
deep: true
},
// 该回调将会在侦听开始之后被立即调用
d: {
handler: function (val, oldVal) { /* ... */ },
immediate: true
},
// watch vm.e.f's value: {g: 5}
'e.f': function (val, oldVal) { /* ... */ }
}
})
watch对象里的属性会在实例化的时候通过$watch()来调用,也就是
watch:{
a: function(val,oldVal){
console.log(val)
}
}
//上面的代码会在实例运行后自动调用,也就是调用this.$watch所以上面的代码就相当于变成了
this.$watch('a',function(val,oldVal){console.log(val)})
//这时候watch里面的键的函数就变成了这里的回调函数了