计算属性

VUE的模板语法非常的方便,我们可以轻松地调用和计算数据,但是如果最终结果和依赖数据之间的关系复杂,直接使用模板语法使得代码易读性极具下降,这里我们借用一下官网的例子

1
2
3
<div id="example">
{{ msg.split('').reverse().join('') }}
</div>

如果我们想要在多个地方使用翻转后的字符串,那么这个冗长的代码就会出现在多个地方,这并不是我们所希望看到的

你可以会说可以使用函数,这确实是一个可行的途径

1
2
3
4
5
methods: {
revMsg: function () {
return this.msg.split('').reverse().join('')
}
}

但是在每个位置我们都需要去调用这个函数,并且即使原字符串没有改变,还是要在函数内进行一次计算,为了节省计算时间,我们希望保存一个值,当原字符串变动的时候才调用函数计算更新这个值,ok,VUE提供了这个功能 —— 计算属性

计算属性可以缓存数据,会自动随着依赖数据改变而改变,当依赖数据没变化时,直接调用计算属性不会重复计算,而是直接得到缓存的值

计算属性的写法和methods完全一样,只是放在参数data对象的computed对象中,调用的时候直接写计算对象的名字即可,不需要像函数一样加括号

1
2
3
4
5
computed: {
revMsg: function () {
return this.msg.split('').reverse().join('')
}
}

多重依赖

计算属性是允许多重依赖的,当其中一个依赖数据发生变化时,就会重新计算刷新缓存,举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
var options = {
el: "#app",
data: {
xing: "张",
ming: "三"
},
computed: {
xingming: function () {
return this.xing + this.ming
}
}
}
var app = new Vue(options)
1
2
3
4
5
<div id="app1">
姓:<input type="text" v-model="xing"/>
名:<input type="text" v-model="ming"/>
<h3>姓名:{{xingming}}</h3>
</div>

当我们修改姓或者名时,姓名这个计算属性就会刷新

计算属性的修改

有时候我们会有直接修改计算属性的需求,比如让用户直接输入姓名,然后系统拆解为姓和名,修改一下HTML做个试验

1
2
3
4
5
6
<div id="app1">
姓:<input type="text" v-model="xing"/>
名:<input type="text" v-model="ming"/>
<h3>姓名:{{xingming}}</h3>
姓名:<input type="text" v-model="xingming"/>
</div>

当我们尝试在input中直接修改xingming这个计算属性的时候会发现控制台有个报错

vue.js:634 [Vue warn]: Computed property “xingming” was assigned to but it has no setter.(found in )

意思是存在计算属性xingming,但是没有setter

计算属性中有两个自带的方法,get和set,之前的写法默认是只有get,也就是只允许获取,不允许修改,如果想要计算属性可以修改,我们需要写一个set方法

实现方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
computed: {
xingming: {
get: function () {
return this.xing + this.ming
},
set: function (val) {
if (val) {
// 默认拆分第一个字符为姓
this.xing = val[0]
// slice(st,en) 提取字符串片段
this.ming = val.slice(1, val.length)
} else {
// 若字符串为空,则不能拆分,否则会变成undefined
this.xing = ""
this.ming = ""
}
}
}
}

这样我们修改xingming这个计算属性,就可以发现依赖属性xingming也跟着变动了

监听

计算属性可以监听到依赖属性的变化,来改变属性值,也可以监听计算属性的变化来更新依赖属性,除此之外,VUE还提供了一个更通用的方法watch,来监听数据的变化,如果属性值发生变化,就执行对应的函数

举个简单的例子,我们在刚才那段代码的姓名显示dom上绑定一个style,然后监听xing属性的变化来改变它的style

1
2
3
4
5
6
7
<div id="app1">
姓:<input type="text" v-model="xing" />
名:<input type="text" v-model="ming" />
<!-- 绑定style -->
<h3 :style = "styleObj">姓名:{{xingming}}</h3>
姓名:<input type="text" v-model="xingming" />
</div>
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
var options = {
el: "#app",
data: {
xing: "张",
ming: "三",
styleObj: {
background: "skyblue"
}
},
computed: {
xingming: {
get: function () {
return this.xing + this.ming
},
set: function (val) {
if (val) {
this.xing = val[0]
this.ming = val.slice(1, val.length)
} else {
this.xing = ""
this.ming = ""
}
}
}
},
watch: {
xing: function () {
let red = parseInt(Math.random() * 255)
let blue = parseInt(Math.random() * 255)
let green = parseInt(Math.random() * 255)
this.styleObj.background
= `rgba(${red},${green},${blue},${Math.random()})`
}
}
}

我们发现每次改变xing变量,都可以触发dom背景颜色的变化,包括xingming这个计算属性的变化带动的xing变量的变化

但是计算属性监听是无法达到理想的效果的,我尝试监听了一下xingming这个计算属性,发现只能监听到xing的变化,ming的变化无法被监听到,也就是说只能watch变量

watch中的函数还有两个自带的参数 newValue, oldValue,记录了原值和修改后的值,我们可以通过如下方法来使用这两个参数

1
2
3
4
5
6
7
8
9
10
watch: {
xing: function (newValue, oldValue) {
console.log(`${oldValue}->${newValue}`)
let red = parseInt(Math.random() * 255)
let blue = parseInt(Math.random() * 255)
let green = parseInt(Math.random() * 255)
this.styleObj.background
= `rgba(${red},${green},${blue},${Math.random()})`
}
}