Vue3 计算属性
Vue3 计算属性
1. 计算属性的由来
1.1 普通模板表达式(有缺陷)
<template>
<span>Name: {{ author.name }}</span>
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
</template>
<script setup>
import { reactive } from 'vue'
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
</script>
<style lang="scss" scoped></style>

上面代码中
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
这行代码虽然能够解决问题,但是有存在一些缺陷:
(1)只能写表达式,不能够写复杂的语句,意味着不能进行复杂的运算;
(2)不够直观,每次都需要完整看完,才能明白表达式的含义;
(3)如果重复使用,代码会变得十分臃肿,并且难以维护。
1.2 计算属性(解决以上问题)
为了解决以上问题,计算属性应运而生。
<template>
<span>Name: {{ author.name }}</span>
<p>Has published books:</p>
<span>{{ isPublishBook }}</span>
</template>
<script setup>
import { reactive, computed } from 'vue'
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
const isPublishBook = computed(() => {
// 在计算属性里面,我们就对数据进行二次处理
return author.books.length > 0 ? 'Yes' : 'No'
})
// 计算属性也是响应式,当依赖的数据发生变化,计算属性则会重新计算
setTimeout(() => {
author.books = []
}, 2000)
</script>
<style lang="scss" scoped></style>

2s后
(1)计算属性的书写方式类似函数,支持复杂的运算;
(2)计算属性命名可自定义,一目了然;
(3)依赖于内部的数据,一处变化,处处变化。
完美解决使用模板表达式的缺陷。
当然啦,如果只是一处简单使用,表达式也许更加方便快捷,看情况而定。
2. 可写计算属性(通过结果,逆向修改依赖值,不推荐)
通常情况下,计算属性的作用就是通过(修改)内部的值从而得到需要的值(就是计算属性)。通常来说,这是单向的。
但是可写计算属性就颠覆了这一过程,通过在set函数,可以反向修改其依赖的内部值。比如:
<template>
<div>{{ firstName }}</div>
<div>{{ lastName }}</div>
<div>{{ fullName }}</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Sheldon')
const lastName = ref('Zhou')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[firstName.value, lastName.value] = newValue.split(' ')
}
})
setTimeout(() => {
fullName.value = 'Michael Jackson'
}, 3000)
</script>
<style lang="scss" scoped></style>


3s后
3. 最佳实践
3.1 Getter 不应该有副作用
所谓副作用,就是我们在做一件事时,导致其他一些不好的事情发生了。
计算属性的副作用也很简单,就是我们在使用 getter 获取希望得到的值时,不要进行修改其他数据、更改DOM、异步请求等操作,因为这都有可能造成一些副作用,从而造成疑惑,因为没人会想到你会在计算属性中做这些事儿。
常见的副作用操作如下:
- 发送网络请求
- 在函数体内修改外部变量的值
- 使用 console.log 等方法进行输出
- 调用存在副作用的函数
- 调用系统 I/O 的 API
3.2 避免直接修改计算属性值
其实就是不推荐使用可写计算属性,因为按照思维惯性,计算属性就应该是根据依赖变化得到的值,相当于一个“临时快照”,通过快照修改原来的依赖,这会显得十分诡异。因此非常不推荐,正常情况下,应该是自然修改依赖,从而改变计算属性的值。
4. 计算属性和方法的区别
4.1 模板中,计算属性重新计算依赖于内部响应式数据变化,方法重新计算依赖于视图变化
计算属性依赖于响应式数据,然后对响应式数据进行二次计算。只有在响应式数据发生变化的时候,才会重新计算,换句话说,计算属性会缓存所计算的值。
而方法在重新渲染的时候,每次都是重新调用。
<template>
<button v-on:click="a++">A++</button>
<button v-on:click="b++">B++</button>
<p>computedA: {{ computedA }}</p>
<p>computedB: {{ computedB }}</p>
<p>methodA: {{ methodA() }}</p>
<p>methodB: {{ methodB() }}</p>
</template>
<script setup>
import { ref, computed } from 'vue'
const a = ref(1)
const b = ref(1)
// 创建两个计算属性,分别依赖 a 和 b
const computedA = computed(() => {
console.log('计算属性A重新计算了')
return a.value + 1
})
const computedB = computed(() => {
console.log('计算属性B重新计算了')
return b.value + 1
})
function methodA() {
console.log('methodA执行了')
return a.value + 1
}
function methodB() {
console.log('methodB执行了')
return b.value + 1
}
</script>
<style lang="scss" scoped></style>

点击按钮A++后,计算属性中只有computedA触发了更新,但是只要视图发生更新,methodA和MethodB也会被重新触发计算。

如果将模板中的关于A的代码进行注释
<button v-on:click="a++">A++</button>
<button v-on:click="b++">B++</button>
<!-- <p>computedA: {{ computedA }}</p> -->
<p>computedB: {{ computedB }}</p>
<!-- <p>methodA: {{ methodA() }}</p> -->
<p>methodB: {{ methodB() }}</p>

你就会发现,不同于之前,无论你怎么点击A++,因为视图没有发生改变,因此根本不会触发methodA和methodB,更别说对应的依赖属性了。
4.2 每次变化,计算属性只计算一次,方法有几次计算几次
每次变化,得益于缓存机制,计算属性只计算一次;
而方法没有缓存,有几次计算几次。
<template>
<button v-on:click="a++">A++</button>
<p>computedA: {{ computedA }}</p>
<p>computedA: {{ computedA }}</p>
<p>computedA: {{ computedA }}</p>
<p>methodA: {{ methodA() }}</p>
<p>methodA: {{ methodA() }}</p>
<p>methodA: {{ methodA() }}</p>
</template>
<script setup>
import { ref, computed } from 'vue'
const a = ref(1)
// 创建两个计算属性,分别依赖 a 和 b
const computedA = computed(() => {
console.log('计算属性A重新计算了')
return a.value + 1
})
function methodA() {
console.log('methodA执行了')
return a.value + 1
}
</script>
<style lang="scss" scoped></style>


4.3 最佳实践
当数据需要进行二次或以上计算时,使用计算属性即可。
方法通常与事件相关联,作为事件的处理方法进行使用。
上一章 《Vue3 响应式常用API》
下一章 《Vue3 Class 与 Style 绑定》
更多推荐
所有评论(0)