Vue3 Ref 语法糖,告别 .value 的写法

前言 近期,Vue3 提了一个 Ref Sugar 的 RFC,即 ref 语法糖,目前还处理实验性的(Experimental)阶段。在 RFC 的动机(Motivation)中,Evan You 介绍到在 Composition API 引入后,一个主要未解决的问题是 refsreactive 对象的使用。而到处使用 .value 可能会很麻烦,如果在没使用类型系统的情况下,也会很容易错过:

let count = ref(1)function add() { count.value++ }

所以,一些用户会更倾向于只使用 reactive,这样就不用处理使用 refs.value 问题。而 ref 语法糖的作用是让我们在使用 ref 创建响应式的变量时,可以直接获取和更改变量本身,而不是使用 .value 来获取和更改对应的值。简单的说,站在使用层面,我们可以告别使用 refs 时的 .value 问题:
let count = $ref(1)function add() { count++ }

那么,ref 语法糖目前要怎么在项目中使用?它又是怎么实现的?这是我第一眼看到这个 RFC 建立的疑问,相信这也是很多同学持有的疑问。所以,下面让我们来一一揭晓。
1 Ref 语法糖在项目中的使用 由于 ref 语法糖目前还处于实验性的(Experimental)阶段,所以在 Vue3 中不会默认支持 ref 语法糖。那么,这里我们以使用 Vite + Vue3 项目开发为例,看一下如何开启对 ref 语法糖的支持。
在使用 Vite + Vue3 项目开发时,是由 @vitejs/plugin-vue 插件来实现对 .vue 文件的代码转换(Transform)、热更新(HMR)等。所以,我们需要在 vite.config.js 中给 @vitejs/plugin-vue 插件的选项(Options)传入 refTransform: true
// vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue'export default defineConfig({ plugins: [vue({ refTransform: true })] })

那么,这样一来 @vitejs/plugin-vue 插件内部会根据传入的选项中 refTransform 的值判断是否需要对 ref 语法糖进行特定的代码转换。由于,这里我们设置的是 true,显然它是会对 ref 语法糖执行特定的代码转换。
接着,我们就可以在 .vue 文件中使用 ref 语法糖,这里我们看一个简单的例子:

对应渲染到页面上:
Vue3 Ref 语法糖,告别 .value 的写法
文章图片

可以看到,我们可以使用 ref 语法糖的方式创建响应式的变量,而不用思考使用的时候要加 .value 的问题。此外,ref 语法糖还支持其他的写法,个人比较推荐的是这里介绍的 $ref 的方式,有兴趣的同学可以去 RFC 上了解其他的写法。
那么,在了解完 ref 语法糖在项目中的使用后,我们算是解答了第一个疑问(怎么在项目中使用)。下面,我们来解答第二个疑问,它又是怎么实现的,也就是在源码中做了哪些处理?
2 Ref 语法糖的实现 首先,我们通过 Vue Playground 来直观地感受一下,前面使用 ref 语法糖的例子中的 块(Block)在编译后的结果:
import { ref as _ref } from 'vue'const __sfc__ = { setup(__props) { let count = _ref(1)function add() { count.value++ } }

可以看到,虽然我们在使用 ref 语法糖的时候不需要处理 .value,但是它经过编译后仍然是使用的 .value。那么,这个过程肯定不难免要做很多编译相关的代码转换处理。因为,我们需要找到使用 $ref 的声明语句和变量,给前者重写为 _ref,给后者添加 .value
而在前面,我们也提及 @vitejs/plugin-vue 插件会对 .vue 文件进行代码的转换,这个过程则是使用的 Vue3 提供的 @vue/compiler-sfc 包(Package),它分别提供了对