ref vs. 响应式变量
自从引入组合式 API 的概念以来,一个主要的未能解决的问题就是 ref 和响应式对象的使用方式。到处使用 .value 无疑是很繁琐的,并且在没有类型系统的帮助时很容易漏掉。
Vue 的响应性语法糖是一个编译时的转换过程,使我们可以像这样书写代码:
<script setup>
let count = $ref(0)
console.log(count)
function increment() {
count++
}
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
这里的这个 $ref() 方法是一个编译时的宏命令:它不是一个真实的、在运行时会调用的方法。而是用作 Vue 编译器的标记,表明最终的 count 变量需要是一个响应式变量。
响应式的变量可以像普通变量那样被访问和重新赋值,但这些操作在编译后都会变为带 .value 的 ref。比如上面例子中 <script>
部分的代码就被编译成了下面这样:
import { ref } from 'vue'
let count = ref(0)
console.log(count.value)
function increment() {
count.value++
}
计算属性
<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'
]
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
const publishedBooksMessageZh = computed(() => {
const chinese = {"Yes": "是", "No": "否"}
return chinese[publishedBooksMessage.value]
})
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
<span>{{ publishedBooksMessageZh }}</span>
</template>
我们在这里定义了一个计算属性 publishedBooksMessage。computed() 方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 publishedBooksMessage.value 访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
。
计算属性宏函数
<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 publishedBooksMessage = $computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
const publishedBooksMessageZh = $computed(() => {
const chinese = {"Yes": "是", "No": "否"}
return chinese[publishedBooksMessage]
})
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
每一个会返回 ref 的响应性 API 都有一个相对应的、以 $ 为前缀的宏函数。包括以下这些 API:
ref -> $ref
computed -> $computed
shallowRef -> $shallowRef
customRef -> $customRef
toRef -> $toRef
响应性语法糖目前是一个实验性功能,默认是禁用的,需要显式选择使用。在最终确定前仍可能发生变化,你可以查看 GitHub 上的提案与讨论来关注和跟进最新进展。