Vue计算与监听属性
# 计算属性
# 介绍
**计算属性(computed)**用于根据已有的响应式数据(ref、reactive) 计算出新的值。它会自动追踪引用的响应式数据,只在数据变化时重新求值,并且将结果进行缓存,避免数据未变化时重复计算。
# 特点
惰性求值:在模板或代码真正使用时才会执行计算函数。
缓存:只要引用到的数据未发生改变,后续的读取无需重新计算,直接返回上一次的结果,提升渲染性能。
普通函数在其他数据变化导致页面更新时,也会重新执行。而计算属性不会,计算属性只会在自身引用的数据变化时重新执行。
只读或可写:默认只读,也可以提供
set方法实现双向绑定(如表单字段的格式化)。
# 使用场景
- 需要将多个数据经过计算展示的场景。
- 对列表进行过滤、排序、统计等需要提升性能的复杂运算场景。
- 在需要保持派生数据与源数据同步,且不希望每次渲染都重新计算的场景。
# 使用方式
只读:computed(() => ...)
可写:computed({ get(){...}, set(val){...} })
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue测试页面</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<div>{{totalMoney}}</div>
</div>
<script>
// 引入computed函数
const {createApp, ref, computed} = Vue;
createApp({
setup() {
const money_list = ref([298, 998, 198])
const totalMoney = computed(()=>{
let tmp = 0;
for (let i in money_list.value){
tmp += money_list.value[i]
}
return tmp
})
return {totalMoney}
}
}).mount("#app")
</script>
</body>
</html>
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
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
# 过滤框案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue测试页面</title>
<script src="./vue.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div id="app">
<div class="container-fluid">
<div class="row">
<div class="col-md-6 offset-md-3 mt-3 text-center">
<h1>数据过滤</h1>
<input type="text" class="form-control w-50 mt-3 offset-md-3" v-model="filter_text">
<table class="table table-bordered table-hover w-50 mt-3 offset-md-3">
<tbody>
<tr v-if="filteredData.length>0" v-for="(item, index) in filteredData">
<td>{{item}}</td>
</tr>
<tr v-else-if="filter_text.length>0">
<td>查询的数据为空!</td>
</tr>
<tr v-else v-for="(item, index) in content_data">
<td>{{item}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
const {createApp, ref, watch, computed} = Vue;
createApp({
setup() {
const filter_text = ref("");
const content_data = ref(["Hello", "World", "WOW!", "ABCDEFG", "我来了!", "你好世界!", "我是谁,我在哪?"]);
// 直接使用计算属性返回过滤结果
const filteredData = computed(() => {
return content_data.value.filter((item) => item.toLowerCase().indexOf(filter_text.value.toLowerCase()) >= 0)
})
return {
filter_text,
content_data,
filteredData
}
}
}).mount("#app")
</script>
</body>
</html>
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
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
# 监听属性
# 介绍
**监听属性(watch)**用于监听响应式数据,在数据发生变化时执行函数代码。它不返回值,只负责在变化时触发回调函数。
# 特点
- 可获取新旧值:回调函数接收
newVal、oldVal,便于对比处理。 - 深度监听:
deep: true可以监控对象或数组内部属性的变化。 - 立即执行:
immediate: true让监听在组件初始化时立即触发一次。 - 支持多源监听:可以一次监听多个响应式值或返回值函数。
# 使用场景
需要对数据变化执行额外逻辑的场景,如发起网络请求、更新本地缓存、调用第三方库。
# 使用方式
监听单个源:watch(监听的响应式变量名, (newVal, oldVal) => {...})
监听多个源:watch([变量1, 变量2], ([newVal1, newVal2], [oldVal1, oldVal2]) => {...})
使用监听参数:watch(监听的响应式变量名, (newVal, oldVal) => {...}, {deep: true, immediate: true})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue测试页面</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<button @click="count++">计数 +1</button>
<input v-model="name" placeholder="修改姓名"/>
<input type="number" v-model.number="age" placeholder="修改年龄"/>
</div>
<script>
// 引入watch函数
const {createApp, ref, watch} = Vue;
createApp({
setup() {
const count = ref(0)
// 监听单个响应式值
watch(count, (newVal, oldVal) => {
console.log(`count 从 ${oldVal} 变为 ${newVal}`)
})
// 监听多个源
const name = ref('Alice')
const age = ref(30)
watch([name, age], ([newName, newAge], [oldName, oldAge]) => {
console.log(`姓名从 ${oldName} 改为 ${newName}`)
console.log(`年龄从 ${oldAge} 改为 ${newAge}`)
})
// 深度监听对象
const user = ref({address: {city: '北京'}})
watch(user, (newVal, oldVal) => {
console.log('user 对象整体变化')
}, {deep: true, immediate: true})
return {count, name, age}
}
}).mount("#app")
</script>
</body>
</html>
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
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