首先向想学习Vue3源码的各位推荐一个学习利器
这个库把 Vue3 源码中最核心的逻辑剥离出来,只留下核心逻辑,以供大家学习。带有详细的中文注释,以及完善的输出,帮助用户理解运行时流程。
简单介绍
今天要讨论的是Vue3中的v-bind,当然不是写在Template中的v-bind,而是写在Style的v-bind。
在Vue3文档的末尾详细地介绍了这个API,它的用法也比较简单。
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<p>hello</p>
</template>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
那么,它和原始的CSS变量 var()有什么不同呢?
与Var()的不同
当我们使用var()时都需要预先在使用节点的祖先节点中编写所需的CSS变量,如果想要该CSS变量与业务代码中的某些变量产生联动,则需要已内联的方式将JS变量写入节点的Style中
<template>
<p :style="cssVars"></p>
</template>
<script setup>
const textColor = '#fff'
const cssVars = {
'--color': textColor
}
</script>
<style>
p {
color: var(--color);
}
</style>
我们从官方给出的示例中可以看到,使用v-bind可以直接在Style中使用script抛出的变量,在开发过程中可谓是非常方便了。
那么它是怎么做到这一点的呢?
运行流程
graph TD
SFC单文件 --> vue-loader
vue-loader -->|正则匹配出`Style`中`v-bind`所使用的变量名称| cssVars --> compilerScript;
compilerScript -->|编译script|拿到cssVars;
拿到cssVars -->|遍历保存的变量名|useCssVar --> 写入组件的节点中;
源码分析
我们从一个简单的测试实例出发
compileSFCScript是测试时使用的工具函数,主要操作只有两步:分析SFC文件、编译文件。
在parse中,会事先初始化一个描述对象
(compiler-sfc/src/parse.ts:112)
之后将源码传入CompilerDOM.parse解析成vue专属的AST,通过对AST的children进行遍历,获取的template 、script、style等这些代码块,其中style可能会有多个的情况,所以desciptor.styles是个数组。
(compiler-sfc/src/parse.ts:155)
获取到styles之后就要取得样式表中的css Vars
(compiler-sfc/src/parse.ts:263)
(compiler-sfc/src/cssVars.ts:40)
使用正则的方式取得v-bind中的值,储存在vars中并返回
至此就完成了style中值的获取
之后,在compileScript中,判断AST中的cssVars是否有值,有值则拼接上预先编译的文本
(compiler-sfc/src/compileScript.ts:201)
(compiler-sfc/src/cssVars.ts:108)
最后的结果就是测试用例中的内容
解析阶段的任务完成,之后就是使用阶段
在该组件被使用时,通过useCssVars这个API来挂载css变量
(runtime-dom/src/helpers/useCssVars.ts)
使用时遇到的问题
-
与teleport配合 在使用
<teleport>的组件中使用v-bind会使得移动了的节点找不到绑定在根节点中的css变量 -
hash问题 绑定在节点上的变量默认会带有hash值,想要全局管理的
css变量的话就不推荐这种方式了