在 vue
的 SFC
中如何书写 css
在日常的业务开发中,很多都是在 vue
文件中的 style
中使用 scoped
字段来实现 css
样式的。比如本人使用的 vscode
扩展,其默认就是设置成 scoped
格式。
但是,scoped
的原理是属性选择器,直观的结果就是当前组件一些 dom
元素会被加上 data-v-hashId
这样的属性,且生成的 css
的类名,也是类选择器和属性选择器的组合,即 .xxx[data-v-hashId] { color: red }
,且不谈属性选择器的性能劣势,单就直观而看,这样也是不优雅的。
所以我介绍下另一个与 scoped
同级的参数 module
,即使得当前的 css
通过 css modules
解析,且默认会在组件实例上生成一个计算属性 $style
,此时再通过 $style.xxx
进行元素类名的双向绑定即可,即 <div :class="$style.xxx"></div>
。
但是,如果一个组件的 css
类名很多,全部通过 module
去双向绑定,也是个麻烦事,那是不是有什么办法简化?
办法是有的,比如将 $style
中的所有类名,都绑定到当前组件上(与组件内部数据字段不冲突时),此时写法上就简化成了 <div :class="red"></div>
。或者可以根据一定规则生成新的类名,比如统一用相同前缀 cls
,即 <div :class="cls_red"></div>
,可以解决与数据字段命名空间冲突的问题,但是还是存在多次双向绑定的情况。那是否有办法减少双向绑定次数?
有,也是此文档的推荐方式。即,在有作用范围的元素(一般就是根元素)绑定 module
上的一个类名,其内部的类名,通过 css module
的 :global
关键字进行包裹,则不会生成被 css modules
处理后的类名,而是与定义的类名一致,也是全局类名。那么生成全局类名,不是会互相影响吗?会,但如果所有的业务和页面级的 vue
组件,都遵循该规范,理论上就不会相互影响,或影响到的极少。类名的命名冲突这种情况就不谈了。这里会生成至少两层的 css
,即 .hashId .red { color: red }
,应该比类加属性选择器性能更优,可以做个 benchmarnk
。
所以,推荐的写法如下:
<template>
<!-- * 只需要这里双向绑定一次 -->
<div :class="$style.root">
<!-- * 这里仍然使用常规的类名 -->
<div class="red">red</div>
<div class="blue">blue</div>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" module>
.root {
:global {
/* * 在global下,不会hash化,但又进行了scss嵌套,即可生成满足的css了 */
.red {
color: red;
}
.blue {
color: blue;
}
}
}
</style>
实际效果如下,可以通过 element
面板查看细节