你需要知道的 Vue.js 中作用域 CSS 的那点事

前言

首先,我们来回忆一下「CSS 作用域」这一概念,它的本质是通过让每一个选择器成为一个「unique」的存在,这样就自然而然地形成了作用域。

而提到「Vue」中「作用域 CSS」,我想大家应该立即想到以 scoped 的方式形成的带有作用域的 css。但是,值得一提的是,在「Vue」中还支持了一种「作用域 CSS」,即「CSS Module」。

提及 「CSS Module」,想必大家会有点陌生,相信有很多同学在平常开发中都是用 scoped 来实现「Vue」组件中的「作用域CSS」。所以,今天我们就来详细认知一下这两者。

一、scoped 作用域

「scoped 作用域」是「Vue」通过「postcss」来实现对每一个在 scoped 标签中定义的选择器的特殊作用域标识,例如:

<template>
  <div id="app">
    <div class="out-box">
    </div>
  </div>
</template>

<style lang="scss" scoped>
#app {
  .out-box {
    width: 200px;
    height: 200px;
    background-color: #faa;
  }
}
</style>

标识后展示在页面上的:

<div data-v-7ba5bd90 id="app">
    <div data-v-7ba5bd90 class="out-box">
    </div>
</div>

<style>
#app .out-box[data-v-7ba5bd90] {
    width: 200px;
    height: 200px;
    background-color: #faa;
}
</style>

可以看到,本质上是在原有的「选择器」的基础上通过「postcss」加上了一串 attr

并且,在我们平常开发中,很常见的场景就是我们在使用一些已有的组件或第三方组件时,我们需要对原有组件的样式进行一些微小的改动。那么,这个时候就需要使用穿透来实现样式的改动,例如:

<style>
div >>> .out-box {
    background-color: #aaf;
}
</style>

这里需要注意的是 >>> 只是一种穿透方式,并不是所有场景下都是可以用 >>> 实现。例如,「iView」需要使用 /deep/ 的方式,「ElementUI」需要使用 ::v-deep 的方式。

二、CSS Module 作用域

相比较「scoped 作用域」,「CSS Modeul 作用域」它所具备的能力更强,所以内容也相对较多。

什么是 CSS Module

「CSS Module」指的是可以将一个定义好的「CSS」文件以变量的形式导入,然后通过使用这个变量对「HTML」中的元素进行样式的修饰,例如:

a.css

.box {
    width: 100%;
    height: 100%;
    background-color: #afa;
}

b.js

import style from './a.css'

const boxElem = document.createElement('div');
boxElem.className = style.box

然后,渲染到页面的时候,它对应的 HTML 看起来会是这样:

<div class="a-box_jlpNx"></div>

可以看出,此时的「类选择器」同样是随机生成的,这也是「CSS Module」形成作用域的所在。

值得一提的是,「CSS Module」还具备其他的能力,例如可以定义全局的「选择器」,写起来会是这样:

:global(.title) {
  color: green;
}

接下来的使用和局部的一样。至于,其他用法,有兴趣的同学可以去 GitHub 上自行阅读

CSS Module 在 Vue 中的应用

回到本文所说的,在「Vue」中也对「CSS Module」做了相应的支持,当我们在 style 标签上添加 module 属性时,「Vue」 会在当前「组件实例」上注入一个计算属性 $style,然后我们可以通过 $style 来使用我们定义好的「选择器」,例如:

HelloWorld.vue

<template>
  <div>
    <div :class="$style['inner-box']"></div>
  </div>
</template>

<style lang="scss" module>
.inner-box {
  width: 100px;
  height: 100px;
  background-color: #aaf;
}
</style>

然后,它渲染到页面时,对于的 HTML 会是这样:

<div class="HelloWorld_inner-box_jlpNx"></div>

那么,这个时候,又回到和「scoped 作用域」一样的问题,使用了「CSS Module」来定义组件的样式,那么我在使用它的时候,如何进行覆盖?

标准的答案,对于「CSS Module」并没有覆盖的说法,有的只是为一个组件设置不同的主题。

但是,如果真的需要弄,那只能通过对该模块对应的 style 标签中定义你需要的样式,然后根据传入组件的 props 来动态绑定 class

那么,为组件设置主题,我们需要在设计组件的时候,对这个组件预留 props ,并将该 props 添加到 $style 中,然后在这个组件中的相应元素中使用,例如:

Box.vue 组件

<template>
  <div>
    <div :class="$style[themeColor]"></div>
  </div>
</template>

<script>
export default {
  props: {
    themeColor: {
        type: String,
        default: 'line'
    }
  }
};
</script>

<style lang="scss" module>
.line {
  width: 100px;
  height: 100px;
  background-color: #aaf;
}
.card {
  background-color: #aaf;
}
</style>

然后,我们在使用该组件的时候通过 props 传入 line 或者 card,从而实现切换组件不同的背景色。

三、两种方式的优劣势

「scoped 作用域」:

  • 对组件没有硬性要求
  • 不易于管理组件样式,需要借助第三方变量定义支持
  • 易于覆盖组件样式,即通过穿透来实现对样式的覆盖

「CSS Module 作用域」:

  • 适合于高度沉淀下的组件使用
  • 易于管理组件样式,即可以通过 style 管理组件中的选择器
  • 组件样式无法通过外部直接覆盖

这里所说的管理,是指通过JavaScript便捷地控制组件样式。

写在最后

其实,对比「scoped」和「CSS Module」两者,各有千秋。至于,要用哪一着得看具体需求,建议大项目中可以使用「CSS Module」,小项目的话用用「scoped」应该绰绰有余。

写作不易,如果你觉得有收获的话,可以帅气三连击!!!

原文链接:juejin.im

上一篇:设计模式(五)创建型设计模式
下一篇:图扑推出可视化智慧仓储管理系统,能否解决购物狂欢节后新一轮爆仓危机?

相关推荐

  • 😀一个原生js弹幕库,基于 CSS3 Animation

    BulletJs 😀一个原生js弹幕库,基于 CSS3 Animation 项目地址 演示图 2020-08-13更新 采用rollup打包并发布到npm,rollup打包教程...

    14 天前
  • 🔥 从最近流行的一幅 CSS 风景画中学习 2 个知识点

    最近 CodePen 流行的一张用纯 CSS 绘制的风景画令人印象深刻: 天空的眩光,睡眠反射,精细的房屋细节相当惊艳,下面我们大致说一说这张图片中的一些技术细节。图画的源码地址在文末。

    8 个月前
  • 💫 CSS 幻术 | 抗锯齿

    前言 传统网页的呈现是基于像素单位的,所以图片不能和 SVG 一样进行任意尺寸缩放后还保持边缘平整。也就是说,放大像素逻辑的图片,必然导致可视质量下降(信息失真)。

    6 个月前
  • 💖CSS + JS 送学妹满屏幕小爱心

    故事开始 午饭时间,暗恋已久的学妹拉着我的衣袖:“学长学长,你能不能让这些爱心变成五颜六色的吗~”。 我在旁边笑开了花~~~ 诶呀,口水流出来了。

    7 个月前
  • (译)CSS 定位与层叠上下文(Stacking context)

    你是否在使用定位时,会遇到一个定位元素即使设置更高的层级,也无法将另一个定位元素覆盖的情况?通过理解层叠上下文,你就能更好的构建你的应用。理解渲染流程和层叠顺序当浏览器将 HTML 解析成 DOM 结...

    2 个月前
  • 黑魔法之 CSS Entry

    大家都知道 webpack 的 Entry 都是 js,如果想输出 css 文件只能在 js 文件里导入 css,所以很多人都会想要是 entry 也可以是 css 那多好,这样就可以任意输出 cs...

    2 年前
  • 高度等于动态宽度(CSS流体布局)[复制品]

    web-tikiThomas Norman提出了一个问题:Height equal to dynamic width (CSS fluid layout) [duplicate],或许与您遇到的问题类...

    3 年前
  • 面试题CSS盒子模型,左右固定宽度,中间自适应的五种死法

    面试题目 假设高度已知,请写出三栏布局,左右300px,中间自适应 有几种方法呢? 最容易的应该想到利用float来写,代码如下 css样式代码,以下五种都是用一个样式代码 &lt;sectio...

    2 年前
  • 面试必备! CSS知识点总结

    一、 元素水平垂直居中的方法 水平居中 行内元素:text-align:center 已知元素的宽度 设置margin:0 auto 元素的宽度不确定 flex 布局 justify-...

    5 个月前
  • 面试官:谈谈你对 CSS 盒模型的认识?(你确定会?)

    题目:谈谈你对 CSS 盒模型的认识 涉及知识点(层层递进): 基本概念:标准模型+ IE模型(区别) CSS如何设置这两种模型 JS如何设置获取盒子模型对应的宽和高 实例题(根据盒模型解释边距...

    2 年前

官方社区

扫码加入 JavaScript 社区