vue computed计算属性

Vue中的计算属性是所有属性的计算,而这些计算都是变向的在过滤值,通过数据的不断变化计算出来不同的值和操作不同的方法. 而在Vue中,会使用到计算属性的场景常见的有:
1.模板内的表达式
2.属性v-bind内可以进行的表达式
3.指令中可以进行的表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
<p @click="count++">{{count+'分'}}</p>
<input v-model='message'>
<p>{{message.split('').reverse().join('') }}</p>
</div>
</template>
<script>
export default {
data () {
return {
count : 0,
message : ''
}
}
}
</script>

我们可以看到
1.在模板内使用了字符串拼接undefined分
2.通过v-bind绑定了一个click事件,button每点击一次,count值就加1,注意,这里并没有使用methods方法
3.input通过v-model进行了数据双向绑定,绑定了message,并且在p标签中对message进行了字符串反转,这里的操作语义化并不是很明显,更好的方法是用filter
filter的优势
filter给我们用于计算和过滤一些模板表达式和v-bind属性表达式一些弊端的地方进行计算,他会返回当前计算的值,可以进行传参在多地方共用这个过滤方法。
filter的劣势
如果我们要计算多个数据不同变化结合而成的地方那filter就能难过到了,本质上filter我认为就是1v1,对单个数据进行过滤,可以进行传参,同方法,但不同参,非常适用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<input v-model='message'>
<p>{{message | reverseString}}</p>
</div>
</template>
<script>
export default {
data () {
return {
message : ''
}
},
filters : {
reverseString (value) {
if(!value) return ''
value = value.split('').reverse().join('')
return value
}
}
}
</script>

computed

computed可以做哪些,又有什么应用场景呢
他规避了模板语法和filter两个所有的劣势,他的优势在于通过计算所有依赖的数据进行计算,然后返回一个值,记住可以依赖方法里所有的数据,只要一个数据发生变化,则会重新计算,来更新view的改变。
应用场景
我们在玩微博的时候,发微博会有一个字数限制,比如说只限输入160个字符。为了让用户体验更好,在文本域中输入内容的时候,同时有一个提示信息,告诉用户你还能输入多少字符。那么使用Vue来做这样的事情就会显得容易的多。比如下面这个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<textarea v-model="content" :maxlength="totalcount"></textarea>
<p>你还可以输入{{reduceCount}}字</p>
</div>
</template>
<script>
export default {
data () {
return {
totalcount : 160 , //总共只给输入160字
content : ''
}
},
computed : {
reduceCount () {
return this.totalcount - this.content.length
}
}
}
</script>

在computed创建了一个reduceCount,一直在监听文字的字符长度,来再次进行计算,返回值给视图,让视图进行变化。这也是一个很简单的示例。前面也提到过,我们可以监听多个数据,只要一个数据变了,整个方法就会重新计算,然后反馈到视图。有下面这样的场景应用,一场足球比赛的播报信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<template>
<div>
<h1>比赛时间{{time}}s</h1>
<h2>直播播报{{result}}</h2>
<div>
<p>中国队进球数:{{team.china}}</p>
<button @click="team.china++">点击中国队进一球</button>
<p>韩国队进球数:{{team.korea}}</p>
<button @click="team.korea++">点击韩国队进一球</button>
</div>
</div>
</template>
<script>
export default {
created () {
let time = setInterval(()=>{
this.time++
if(this.time == 90){
clearInterval(time)
}
},1000)
},
data () {
return {
time : 0,
team : {
china : 0,
korea : 0
}
}
},
computed : {
result () {
if(this.time<90){
if(this.team.china>this.team.korea){
return '中国队领先'
}else if(this.team.china<this.team.korea){
return '韩国队领先'
}else{
return '双方僵持'
}
}else{
if(this.team.china>this.team.korea){
return '中国队赢'
}else if(this.team.china<this.team.korea){
return '韩国队赢'
}else{
return '平局'
}
}
}
}
}
</script>

1.比赛时间,用time维护
2.比赛双方的进球数有team维护
3.比赛的播报情况,在90分钟内,要显示中国领先或者韩国领先或者双方僵持,如果到了90分钟我们要显示中国队赢还是韩国队赢,还是平局
第三个数据我们需要监听时间和进球数来判断比赛的胜负,computed是观察一个或多个数据,当一个数据变化的时候,他就会重新计算,还有就是通过观察所有数据来维护一个状态,就是所谓的返回一个状态值。

computed vs methods

在Vue中,使用methods可以做computed同样的事情,不同的是,computed可以进行缓存。就是在上个例子中我们对比赛时间和两个球队的进球数进行了检测数据。如果随着时间的改变,但是球数没动,对于computed来说就不会再次计算球数而是进入缓存,重新计算的是这个时间,而且页面的DOM更新也会触发methods来重新计算属性。所以,如果不想让计算属性进入缓存,请使用methods,但我个人更推荐使用computed,语义化会更好一点。毕竟是什么选项里就应该做什么事,methods里面就是应该来管事件的。

computed vs watch

computed,watch都可以对数据进行实时监听,但是应用场景不同。
1.computed是适用对多数据变动进行监听,然后维护一个状态,就是返回一个状态值。
2.watch是对一个数据进行监听,在数据变化时,返回两个值,一个是value(当前值),二是oldvalue是变化前的值。
watch的应用场景主要是监听一个数据进行复杂的逻辑操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
<div>
<h1>比赛时间{{time}}s</h1>
<h2>直播播报{{result}}</h2>
<div>
<p>中国队进球数:{{team.china}}</p>
<button @click="team.china++">点击中国队进一球</button>
<p>韩国队进球数:{{team.korea}}</p>
<button @click="team.korea++">点击韩国队进一球</button>
</div>
</div>
</template>
<script>
export default {
created () {
let time = setInterval(()=>{
this.time++
if(this.time == 90){
clearInterval(time)
}
},1000)
},
data () {
return {
time : 0,
team : {
china : 0,
korea : 0
},
result : "双方僵持"
}
},
watch : {
time (value,oldval) {
if(value<90){
if(this.team.china>this.team.korea){
this.result = '中国队领先'
}else if(this.team.china<this.team.korea){
this.result = '韩国队领先'
}else{
this.result = '双方僵持'
}
}else{
if(this.team.china>this.team.korea){
this.result = '中国队赢'
}else if(this.team.china<this.team.korea){
this.result = '韩国队赢'
}else{
this.result = '平局'
}
}
},
team (value,oldval){
if(this.time<90){
if(value.china>value.korea){
this.result = '中国队领先'
}else if(value.china<value.korea){
this.result = '韩国队领先'
}else{
this.result = '双方僵持'
}
}else{
if(value.china>value.korea){
this.result = '中国队赢'
}else if(value.china<value.korea){
this.result = '韩国队赢'
}else{
this.result = '平局'
}
}
}
}
}
</script>

以上代码和computed产生的效果是一模一样,但是很明显,就像我对computed和watch阐述过了应用场景,这个场景只是维护了一个比赛状态,而不牵扯到逻辑操作。虽然也能完成,但无论从代码量的比对还是可读性,还是可维护性的都不胜于computed。但说到底谁更强大呢?我还是老实说watch更强大,虽然他也有场景的局限性,但是他可以做牵扯到计算属性的一切操作,缺点是watch只能一个一个监听。

总结

Vue官方有一句话说得很重要:

1
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的watcher。这是为什么Vue提供一个更通用的方法,使用wacth来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。

所以根据不同的场景使用不同的方法

computed

监听一个或者多个数据维护返回一个状态值,如果其中一个或者多个数据发生变化,则会重新计算整个函数体,返回一个新的状态值

watcher

只能一个一个监听数据,数据发生变化时返回两个参数,第一个是当前值,第二个是变化前的值。每当数据变化的时候,会触发函数体的逻辑操作,根据逻辑行为进行后续的操作。