计算属性与侦听器
# 计算属性与侦听器
对于任何包含响应式数据的复杂逻辑,都应该使用计算属性而非在模板中直接计算。侦听器则用于在数据变化时执行副作用。本章分别用 Options API 和 Composition API 两种风格演示。
# 计算属性
在如今编程都提出 MVC、MVP 或 MVVM 等模式的情况下,已经很少再将业务逻辑和视图层合在一起。
在 Vue3.0 中,在 HTML(相当于视图层)插值方式是可以负责计算(相当于业务逻辑),但不提倡你这么用,因为 Vue3.0 有计算属性。
# 1 计算属性
将计算放置在模板中,模板将不再是简单的和声明性的,此时,你必须先看一下它,然后才能意识到它执行的计算取决于 chen.lang。如果要在模板中多次包含此计算,则问题会变得更糟。
所以,对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性,听到了没?如果没有的话,那就看看代码吧。计算属性放在 computed 里面,函数放在 methods 里面。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vue3.0计算属性</title>
<script src="vue.global.js"></script>
</head>
<body>
<span id="app">
<span>在插值中计算的结果:{{ chen.lang.length > 10 ? '太多了' : '还好' }}
</span>
<br/>
<span>获取计算属性的结果:{{ langCount }}</span>
</span>
<script>
Vue.createApp({
data() {
return {
chen: {
name: 沉梦听雨
lang: [
'Python',
'前端',
'小程序',
'Java',
'Android App',
'iOS App'
]
}
}
},
computed: {
// 计算属性的 getter
langCount() {
return this.chen.lang.length > 10 ? '太多了' : '还好'
}
}
}).mount("#app")
</script>
</body>
</html>
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
细心的朋友,可能就会问了,那我用函数计算行不行。如果不考虑性能的话,当然可以的。只是函数和计算属性的区别在于,计算属性有缓存的作用,而函数没有。
在操作过程中,如果内容没有改变,计算属性不会重新计算,而函数每次都会进行计算。用函数计算的代码,我发出来,你自己拷贝进去就好。
<!-- 新增函数计算部分 -->
<br/>
<span>函数计算属性的结果:{{ langFun() }}</span>
,
methods: {
// 函数中
langFun() {
return this.chen.lang.length > 10 ? '太多了' : '还好'
}
}
2
3
4
5
6
7
8
9
10
# 2 计算属性的 Setter
计算属性默认只有 getter,如果你想要一个 setter 的话,手动加上就好。
在函数里更新计算属性数据时,会调用 setter。你可以在 setter 里进行调整。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vue3.0计算属性</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<span id="app">
<p>{{ fullName }}</p>
<p>{{ firstName }}</p>
<p>{{ lastName }}</p>
<button @click="sayHello()">点击调用set方法</button>
</span>
<script>
Vue.createApp({
data() {
return {
firstName: '程',
lastName: '绪媛'
}
},
computed: {
// 计算属性
fullName: {
//getter
get() {
return this.firstName + '' + this.lastName
},
//setter
set(newValue) {
const names = newValue.split('或')
this.firstName = names[0]
this.lastName = '没有' + names[names.length - 1]
}
}
},
methods: {
// sayHello: function() {
// this.fullName = '程绪媛'
// }
sayHello() {
this.fullName = '程绪媛'
}
},
}).mount("#app")
</script>
</body>
</html>
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
运行结果

点击调用 set 方法后

# Composition API 写法
在 <script setup> 中,使用 computed 函数定义计算属性。
有时在数据展示时要做简单的计算
<script setup lang="ts">
import { ref } from 'vue'
const firstName = ref('三')
const lastName = ref('张')
</script>
<template>
<h2>{{lastName + firstName}}</h2>
<h3>{{lastName + firstName}}</h3>
<h4>{{lastName + firstName}}</h4>
</template>
2
3
4
5
6
7
8
9
10
11
12
看起来较为繁琐,可以用计算属性改进
<script setup lang="ts">
import { ref, computed } from 'vue'
const firstName = ref('三')
const lastName = ref('张')
const fullName = computed(() => {
console.log('enter')
return lastName.value + firstName.value
})
</script>
<template>
<h2>{{fullName}}</h2>
<h3>{{fullName}}</h3>
<h4>{{fullName}}</h4>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- fullName 即为计算属性,它具备缓存功能,即 firstName 和 lastName 的值发生了变化,才会重新计算
- 如果用函数实现相同功能,则没有缓存功能
<script setup lang="ts">
import { ref } from 'vue'
const firstName = ref('三')
const lastName = ref('张')
function fullName() {
console.log('enter')
return lastName.value + firstName.value
}
</script>
<template>
<h2>{{fullName()}}</h2>
<h3>{{fullName()}}</h3>
<h4>{{fullName()}}</h4>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 侦听器(watch)
在输入框输入数据时,有时候,你需要实时获取到用户输入的每一个字符,才好在后台进行相关处理,像搜索引擎就是这样的。
在 Vue3.0 中,侦听用户输入,使用 watch 方法。
文本框输入一个广字,后台调用天气查询接口,这时有可能返回广州,也有可能返回广平等含有广字的城市的天气信息。当输入广州时,会再去查询一遍。侦听器一监听到有内容变化,就会去调用天气查询接口,再次查询数据。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.global.js"></script>
<script src="axios.min.js"></script>
</head>
<body>
<div id="app">
<p>{{ weather }}</p>
<input v-model="city" placeholder="请输入城市名称"/>
</div>
<script>
Vue.createApp({
data() {
return {
weather: '',
city: ''
}
},
watch: {
city(newCity, oldQuestion) {
this.getWeather()
}
},
methods: {
getWeather() {
this.weather = '查询' + this.city + '天气中..'
axios
.get('http://wthrcdn.etouch.cn/weather_mini?city=' + this.city)
.then(response => {
this.weather = response.data
})
.catch(error => {
this.weather = '获取不到:' + error
})
}
}
}).mount("#app")
</script>
</body>
</html>
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
# Composition API:watch
利用监听器,可以在【响应式】的基础上添加一些副作用,把更多的东西变成【响应式的】
原本只是数据变化 => 页面更新
watch 可以在数据变化时 => 其它更新
<template>
<input type="text" v-model="name" />
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
function useStorage(name: string) {
const data = ref(sessionStorage.getItem(name) ?? "");
watch(data, (newValue) => {
sessionStorage.setItem(name, newValue);
});
return data;
}
const name = useStorage("name");
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 名称为 useXXXX 的函数,作用是返回带扩展功能的【响应式】数据
- localStorage 即使浏览器关闭,数据还在
- sessionStorage 数据工作在浏览器活动期间