前言
在开始正片之前,还是先抛一块砖👇
最近在写自己的小项目,引入了
NProgress
作为页面加载的进度条,但是感觉内置的background-color
和项目的主题不太搭,所以打算换一个背景色,由此引出了一个scoped
的问题
通过在度娘一番搜索,我很快就找到了替换background-color
的解决方法👇
/* App.vue */
#nprogress .bar{
background: red !important;
}
然而就在我按下crtl s
的时候,却发现样式并没有生效,在反复刷新之后仍然没有生效。这时我想着要不直接改nprogress.css
文件算了,但是身体里不羁的内卷灵魂阻止了我的行动,于是乎就有了本文的启发
这时我发现在<style>
标签上有一个scoped
属性,由于在App.vue
文件中有一些特定的样式,因此加上了scoped
保护属性不重名,才导致了上面样式的不生效
因此我把这个样式抽离到了全局CSS文件
中,然后直接引入到main.ts
,就实现了background-color
的修改
由此引伸出两个问题:
1. 为什么使用了
scoped
就能防止样式污染?2.
scoped
是怎么工作的?
为什么使用了scoped
就能防止样式污染
首先我们来创建一个Vue
项目看一下网页中的效果(这里使用的是Vue3 + Vite
进行演示)
我们可以看到编译出来的html文档
中,为元素添加了[data-v-hash]
属性
在控制台中,也为添加了scoped
属性的<style>
标签中的选择器
加上了[data-v-hash]
在Vue3
的官方文档中是这样解释的👇
当
<style>
标签带有scoped
attribute 的时候,它的 CSS 只会应用到当前组件的元素上。这类似于 Shadow DOM 中的样式封装。它带有一些注意事项,不过好处是不需要任何的 polyfill。它的实现方式是通过 PostCSS 将以下内容:
<style scoped> .example { color: red; } </style> <template> <div class="example">hi</div> </template>
转换为:
<style> .example[data-v-f3f3eg9] { color: red; } </style> <template> <div class="example" data-v-f3f3eg9>hi</div> </template>
简单地说就是通过为html元素
和选择器
加上特殊的标识符,来达到唯一属性的目的,就不会污染全局环境
那么这种方式是怎么实现的呢?接着往下看
scoped
是怎么工作的?
在上面的Vue3
官方文档介绍中,提到scoped
功能是由PostCSS
实现的,那么我们来看看具体使用了什么插件
下面是Vue3
的部分源码👇最终可以定位到postcss-modules-scope
这个插件
// compiler-sfc.cjs.js
const plugin = (options = {}) => {
const generateScopedName =
(options && options.generateScopedName) || plugin.generateScopedName;
const generateExportEntry =
(options && options.generateExportEntry) || plugin.generateExportEntry;
const exportGlobals = options && options.exportGlobals;
return {
postcssPlugin: "postcss-modules-scope",
...
};
};
在官方的npm文档中可以了解到,这个插件可以将CSS类
转换成CSS Module
,这也就是为什么不用担心污染全局作用域的原因
把下面的代码👇
:local(.continueButton) { color: green; }
转换为👇
:export { continueButton: __buttons_continueButton_djd347adcxz9; } .__buttons_continueButton_djd347adcxz9 { color: green; }
因此可以用下面这种方式直接在JS中使用,而不用担心污染全局作用域
import styles from "./buttons.css"; elem.innerHTML = `<button class="${styles.continueButton}">Continue</button>`;
至于最终编译成控制台中的html文档
形式,由于本人能力有限,目前对Vue3
的源码理解还处于非常浅薄的状态,如果之后有更深入的理解再更新文章(希望有大佬能在社区科普一下^_^)
结语
本来这篇文章是打算深入学习一下Vue3
源码的,但是无奈本人能力有限还不能很好的理解其中的原理, 如果有任何需要修改或者错误的地方,恳请指出,感激不尽