序言
《Vue 3:2020年中状态更新》的时候,文中曾经提到过尤雨溪希望7月中旬发布RC版(候选版本),8月初发布3.0正式版。
不过现在已经八月初了怎么还是没发布呢?这个月初到底几号才算是"初"呢?于是我赶紧去github上看看现在到底有没有什么风吹草动,看着看着溘然创造一个非常好玩的特性,这个特性我以前就常常这么想:假如我在data里面定义的变量也能在CSS里面用那该多好啊!
(大家有没有也这么想过)
以前做项目的时候常常会这么想:

<template><h1>{{color}}</h1></template><script>exportdefault{data(){return{color:'red'}}}</script><style>h1{color:this.color;}</style>
当然,想想也知道不可能,JS和CSS从属不同高下文,CSS哪来的this呢?
那么怎么才能在CSS中利用JS变量呢?那就只能用JS操作DOM然后把变量塞进style里了,比如用ref获取到DOM元素,然后dom.style.color = this.color。
或者在模板里:
<template><h1:style="{color}">Vue</h1></template><script>exportdefault{data(){return{color:'red'}}}</script>
不过这种办法还是有缺陷的,比如本来就不推举把样式写在style属性里,还有便是变量复用会很麻烦,比如一组DOM元素都想用这个变量,那就不得不给这一组起个类名,然后再在mounted里面document.getElementsByClassName(),获取到DOM凑集之后还要循环遍历每个元素,为其加上dom.style.color = this.color,摧残浪费蹂躏了很多的性能。
实在CSS本身有很多毛病,并不图灵完备,以是才导致了各种预处理器的涌现:Sass、Less、Stylus等……
它们为CSS供应了很多特性:循环、条件语句、变量、函数等……
个中有个特性非常有用,那便是变量!
于是CSS也引入了变量的这个观点,自从有了CSS变量,很多事情真的方便了许多,通过JS操作CSS变量,然后再在须要的地方利用CSS变量,这种方法比之前的高效得多。
在JS里(不止JS,所有措辞都差不多),变量有如下几个特性:
声明利用浸染域声明为了方便理解,咱们通过用JS的办法来类比:
var color = 'red';
在CSS中等同于:
--color: red;
当然这点跟JS不太一样,但是如果你学PHP这类措辞或者Sass的话该当就很好理解了,在PHP或Sass中,声明变量的时候没有一个关键字,而是在变量名的第一位加上一个美元符号$,这就代表声明变量了。
PHP:
$color='red';
Sass:
$color: color;
但是$符号被Sass占用了,@符号被less占了,以是CSS只能想出别的符号了,CSS的符号便是两个减号--
利用光声明一个变量是没有什么太大意义的,只有利用了它,这个变量才算有代价:
JS:
console.log(color)
可以看到var只是个声明变量的关键字,color才是变量名。
PHP:
echo$color;
Scss:
h1 { color: $color;}
但是在PHP或Sass中,声明变量的时候带着,用的时候也得带着。
这就令许多开拓者感到困惑,以是CSS在利用变量的时候用到了一个函数叫var():
CSS:
h1{color:var(--color);}
虽然和PHP、Sass一样,调用时要带着前缀(由于那便是变量名的一部分),但是不一样的是须要用一个var()来把变量包裹起来。
浸染域这个很好理解,不仅JS里有浸染域,CSS里也有浸染域,比如:
JS:
varcolor='red';functionh1(){console.log(color);}functiondiv(){varcolor='blue';console.log(color);}h1();//reddiv();//blue
类似于CSS里的:
body{--color:red;}h1{color:var(--color);/这里获取到的是全局声明的变量,值为red/}div{--color:blue;color:var(--color);/这里获取到的是局部声明的变量,值为blue/}
也便是说,变量的浸染域便是它所在的选择器的有效范围。
中文CSS变量有一次我看到了两个脑洞大开的库,才创造CSS变量还可以这么玩:
chinese-gradientchinese-layout从他俩的名字就可以看出,都是用chinese开头的,那么大概率便是用中文做的CSS变量,点进去一看果不其然。
也便是说CSS变量的原谅性很强,不像以往编程的时候都必须是英文命名,中文这次居然也可以完美运行,不信咱们来试一下:
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title><!--在这里用link标签引入中文布局--><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/chinese-layout"><!--在这里用link标签引入中文渐变色--><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/chinese-gradient"><style>/打消默认样式/{padding:0;margin:0}ul{list-style:none}/全屏显示/html,body,ul{height:100%}/在父元素上写入九宫格/ul{display:grid;grid:var(--九宫格);gap:5px}/给子元素上色/li{background:var(--极光绿)}</style></head><body><ul><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul></body></html>
运行结果:
也便是说,CSS变量可以这样定义:
body{--蓝绿色:aquamarine;}
然后调用的时候:
h1{color:var(--蓝绿色);}
在vue中的变量
那么若何才能在vue3的<style>中利用<script>里声明的变量呢?
首先我们先创建个支持vue3的vite项目:
npm init vite-app vars
然后进入到该文件夹安装依赖:
cd vars
npm i
然后创建一个组件,组件型式长这样:
<template><h1>{{color}}</h1></template><script>exportdefault{data(){return{color:'red'}}}</script><stylevars="{color}">h1{color:var(--color);}</style>
还记得文章一开始写的抱负中的组件是什么样吗:
<style>h1{color:this.color;}</style>
但是就算vue再牛它也不可能给CSS安个this啊,除非再做一个什么预处理器,不过这次利用CSS变量已经可以很靠近咱们抱负中的组件啦:
<stylevars="{color}">h1{color:var(--color);}</style>
首先要在<style>标签中写个vars="{}",再在大括号里写上你在data中声明过的值。
再来试一下这个变量是不是相应式的,动态改变<script>标签中的this.color值会不会引起视图的变革呢?来试一下:
<template><h1>Vue</h1></template><script>exportdefault{data(){return{opacity:0}},mounted(){setInterval(_=>{this.opacity>=1&&(this.opacity=0)this.opacity+=0.2},300)}}</script><stylevars="{opacity}">h1{color:rgb(65,184,131);opacity:var(--opacity);}</style>
运行结果:
可以看到每300毫秒我们就改变一下this.opacity的值,它会映射到CSS变量上去,this.opacity变了,--opacity的值就会随之变革,视图也会随着数据的更新而相应的更新,这个特性切实其实太棒了!
多个变量之间利用逗号进行分隔:
<template><h1>Vue</h1></template><script>exportdefault{data(){return{border:'1pxsolidblack',color:'red'}}}</script><stylevars="{border,color}"scoped>h1{color:var(--color);border:var(--border);}</style>
脑洞大开
既然chinese-gradient和chinese-layout这两个CSS库验证了CSS中文变量的可行性,而且我记得工具的属性也是可以写中文的,那么咱们就来试一下在vue中能不能用这种黑邪术来写中文:
<template><h1>Vue</h1></template><script>exportdefault{data(){return{'透明度':0}},mounted(){setInterval(_=>{this['透明度']>=1&&(this['透明度']=0)this['透明度']+=0.2},300)}}</script><stylevars="{透明度}">h1{color:rgb(65,184,131);opacity:var(--透明度);}</style>
运行结果:
居!
然!
管!
用!
了!
往后大家不会命名的话也别用汉语拼音了,直接写中文吧哈哈!
后续掩护的时候一看变量名就能一览无余(不过还是推举用英文)。
猜也能猜到,大概率是用到了类似于dom.style.setProperty('--opacity', this.opacity)之类的方法,按下f12打开掌握台一看,果不其然,它掌握的是组件元素的style属性:
不过我们刚才在<style>标签中只用到了var,scoped实在也很常用,那么如果他们两个碰到一起去会编译成什么样呢?
<stylevars="{透明度}"scoped>h1{color:var(--透明度);}</style>
运行结果:
可以看到Vue把CSS变量也编译了一个和data-v-后面的那串随机字符一样的:
那么问题来了,如果我假如在全局样式里定义了一个--color属性,我在带有scoped属性的组件里想用这个全局的CSS变量,可是一旦在scoped中利用CSS变量就会被编译成:--62a9ebed-color,可是全局定义的不是--62a9ebed-color而是--color,这样就会涌现找不到全局属性的局势,这个问题要怎么办理呢?实在也很大略,只须要在--的后面加上一个global:就可以了:
<stylevars="{color}"scoped>h1{color:var(--global:color);}</style>
这样编译出来的CSS就会变成:var(--color)啦!
怎么样是不是很好玩?Vue这次更新诚意满满,不过大家都把关注点放在了Composition-API上了,没有把稳到这些不起眼的边边角角,但便是这些边边角角却可以极大的提高我们的开拓体验。
对了,CSS变量也是有兼容性的:
从[caniuse](<https://www.caniuse.com/#search=CSS Variables>)网站上可以看到,它是不兼容IE的,利用的时候记得确认一下自己项目须要兼容的范围。