深入理解 Vue3:style 中的响应式变量如何工作?
前言
在很多业务场景中,我们的 style 样式可能会根据业务逻辑的变化而变化,这个时候大家最容易想到的方案就是多写几个 class 类,根据不同场景应用不同的类,比如这样:
这样虽然也是一种不错的方式,但是如果类型有非常多的话,那么你就得在 vue 模版里面写大量的判断表达式,并且在 style 中写大量的 class 类。
要是在 style 中也可以直接使用 script 中的 JS 变量,那么这种场景处理起来是不是会更方便一点呢?
Vue2 CSS 变量
在 Vue2 中,遇到以上业务场景如果我们不想写大量的 class 类的话,可以借助 css 中的 var()函数来实现
var() 可以插入一个自定义属性(有时也被称为“CSS 变量”)的值,用来代替非自定义属性中值的任何部分。
比如:
在模版中调用 getStyle 函数获取颜色值,并且定义成 css 变量
生成颜色值
然后就可以只写一个 css 类了
这种方案的原理其实就是借助了 CSS 的自定义变量以及 CSS 的作用域来实现的
所以它需要两步:
自定义 CSS 变量(考虑作用域范围)
使用 CSS 变量
实际上在 Vue3 中还有更简便的方案!
Vue3 v-bind()
在 Vue3 单文件组件的 <style> 标签支持使用 v-bind 函数将 CSS 的值链接到组件中的数据。
所以以上场景还可以这样实现:
模版:
计算颜色值:
style 调用 v-bind()使用 setup 中的变量
从该图我们可以发现 Vue3 中的 v-bind()原理与上面的 CSS 变量的原理一样,都是借助了 CSS 的自定义变量以及 CSS 的作用域来实现的
只不过不同的是 v-bind()生成的 CSS 变量前面多了一串 hash
Vue3 是如何编译 v-bind()的?
猜测流程
我们可以从编译结果来进行反推
首先是我们的 JS 部分,编译成了以下内容:
这里会比没使用 v-bind()的组件多出一个_useCssVars()函数
能不能猜到这个函数的作用是什么?如果不能,接着看下面一张图👇
这张图是组件的 style 部分编译之后的产物,可以看到
编译成了
也就是说我们使用的 v-bind 最终也是编译成了原生 CSS 中 var 函数,原理也是使用 CSS 的自定义变量
但是这里只有使用,并没看到 css 变量定义的地方🤔,现在能够猜测到_useCssVars()函数的作用是什么吗?大概率就是用来生成 css 自定义变量了。
接下来我们可以到源码中进行验证:
源码验证
找到源码中的 doCompileStyle 函数,打上断点,然后就可以启动 debug 模式了
接着往下走你会看到一个 shortId 变量,它此时的值是什么呢?
是不是有点眼熟,没错它就是后面会出现在 CSS 变量前面的那一串 hash
再接着往下走,我们可以看到 postcss 插件中添加了一个 cssVarsPlugin 插件
这个插件的作用大家是不是已经猜到是干嘛的了,接着往下走
在 cssVarsPlugin 这个方法中再加一个断点
可以看到此时进来的 decl 参数是:color: v-bind(color)
熟悉 postcss 的同学应该能知道 decl 是什么意思,它表示的是 css 转化为 AST 后的一个节点类型
将 CSS 声明中的属性值 v-bind(color) 经过 vBindRE 正则进行检测是否为 v-bind()语句
再往下,这里就是 v-bind()语句编译的核心代码了
首先是提取变量名
这里可以看到,执行后的结果是'color',也就是 v-bind()括号中的这个变量了
再往下
此时就能看到整个编译结果了:v-bind(color) ---> var(--5d92a9f9-color)
可以看到 v-bind()的编译其实就是通过正则处理重新生成字符串
现在知道 v-bind()是如何编译的,剩下一个重点就是:Vue 是如何把 style 中使用的变量转换成 CSS 变量并设置在对应 dom 节点上的
这个突破点在我们上面猜测流程的第一张图,里面有这样一段代码:
很明显,它就是用来生成 CSS 变量
接下来我们可以在源码中找到这个函数,并打上断点
在源码中搜索_useCssVars,你会发现什么也搜不到,这时我们可以尝试去掉_仔进行搜索,你会发现有这样一段代码:
很明显,后面在源码中我们只需要搜索 CSS_VARS_HELPER 就可以,找到以下代码,打上断点,刷新页面
我们会发现这一段其实就是生成了我们上面那一段代码:
走到这里你会发现好像走不下去了,没有下一步了,因为最终我们看到的编译后的代码就是这个,具体是怎么把 style 中使用的变量转换成 CSS 变量并设置在对应 dom 节点上的这个并不是在编译时处理的。
想搞清楚这个我们还得在运行时打断点调试(这里换成了火狐浏览器进行断点调试,不要问为什么,问就是断点调试比谷歌好用)
接着往下走,会来到 setVars 方法这里
从方法名我们一眼就能看出它就是用来设置 CSS 变量的!
再往下走 setVars -> setVarsOnVNode -> setVarsOnNode
在这里最终会调用 setProperty 方法来设置 css 变量。
到这里整个流程就结束了!
作为程序员,持续学习和充电非常重要,作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。低代码也是一个值得我们深入探索的领域,让我们拭目以待,它将给前端世界带来怎样的变革,推荐一个低代码工具。
开发语言:Java/.net
这是一个基于 Flowable 引擎(支持 java、.NET),已支持 MySQL、SqlServer、Oracle、PostgreSQL、DM(达梦)、 KingbaseES(人大金仓)6 个数据库,支持私有化部署,前后端封装了上千个常用类,方便扩展,框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用。
至少包含表单建模、流程设计、报表可视化、代码生成器、系统管理、前端 UI 等组件,这种情况下我们避免了重复造轮子,已内置大量的成熟组件,选择合适的组件进行集成或二次开发复杂功能,即可自主开发一个属于自己的应用系统。
评论