11 组合式API(二)
摘要:在模板中使用表达式是允许的,但也仅限于一些简单的操作,如自增操作;若在模板中写入太多的逻辑,则会让模板变得臃肿,难以维护;为此,计算属性的提出使得代码尤为简洁。在本文中,我们会详细介绍计算属性。
声明:为了文章的清爽性,在文章内部的代码演示中只会附上部分演示代码。
作者:来自ArimaMisaki创作
11.1 计算属性
说明:在组合式API中,我们希望把模板中应有的逻辑封装为回调函数写到computed()
中,该函数返回的是一个计算属性ref,与一般的ref类似,它会在模板中被自动解包,因此在模板表达式中引用时无需添加.value
。
TS:computed()会自动从其计算函数中的返回值上推导出类型,我们也可以通过泛型参数显式地指定类型。
<script lang="ts" 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'
]
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
11.2 计算属性和方法的优劣
方法:前面我们没有特意地谈论方法是如何定义的,但只要细想就会发现,我们不再依赖于methods选项,而是直接将方法定义为一个函数在模板中直接使用。
说明:使用计算属性和方法的区别看上去实际上别无二致,他们的主要区别我们实际上在4.2.2中已经提及;另外需要补充的是,一个计算属性只会在响应式依赖更新时才会被重新计算,如果我们试图把Date.Now()
放到计算属性的函数中,那是出不来实时更新时间的效果的,因为Date.Now()本身并不是响应式依赖。
<script lang="ts" 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 publishedBooksMessage = ()=>{
return author.books.length > 0 ? 'Yes' : 'No'
}
// 一个计算属性 ref
// const publishedBooksMessage = computed(() => {
// return author.books.length > 0 ? 'Yes' : 'No'
// })
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage() }}</span>
</template>
11.3 可写计算属性
说明:在大多数情况下,我们使用计算属性的时候都是在computed()
中计算好想要的属性并且读取,很少有一种情况说要计算好属性后还直接修改的。当我们尝试去修改一个计算好的属性时,会受到一个运行时警告。如果实在有这方面的需求,我们可以向computed()中传入一个对象参数,该对象包含有get和set方法,get用于读取计算属性,set用于修改计算属性。
提示:虽然可以修改计算属性值,但我们还是要避免这样使用,因为这样做违背了计算属性函数
使用的初衷。
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>