使用VueJS进行应用开发, 脱离不了对应用间的模块进行拆分, 将大块界面拆解为组件的过程. 我们可以很方便的在单文件中使用<template>块维护组件的视图, 使用<script>维护组件的逻辑部分, 使用<style>维护组件的样式. 在我们编写 VueJS 组件样式时, 不得忽略的一点就是样式污染.
样式污染产生原因
提及样式污染, 主要要追溯到Webpack对CSS文件的打包过程, 这里我们以Vue-Element-Admin中的Webpack配置项举例:
const webpackConfig = merge(baseWebpackConfig, {
plugins: [
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash:8].css'),
chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
}),
]})Webpack 使用 MiniCssExtractPlugin 插件, 将文件(如Vue单文件组件)中的CSS代码, 经过处理后, 分离到形如app.hash1234.css的单独的CSS文件:

如果没有加入防止样式污染的措施的同时, 项目中存在了大量的同名 ClassName, 那么可能会产生意想不到的CSS选择器权重覆盖. 这可能使后文件中某部分选择器权重更高的类影响整个应用, 而此过程通常发生在组件的编写中, 所以一般称之为组件样式污染.
Webpack & Vue SFC Object
对于 Vue 项目而言, 使用 Webpack 将极大的优化了工作流程, 因为通过Vue Loader, Vue 单文件组件能很好的融合进 Webpack 工作流中. 通过跟踪源码, 可以发现, 我们写的单文件组件都被处理为了SFC对象, 即包含了单个HTML模块, 单个脚本模块, 一个或多个样式模块, 一个或多个自定义模块的对象:
// vue-loader/index.js
const descriptor = parse({
source,
compiler: options.compiler || loadTemplateCompiler(),
filename,
sourceRoot,
needMap: sourceMap
})// vuejs/component-compiler-utils/index.js
function parse(options) {
const { compiler } = options
output = compiler.parseComponent(source, compilerParseOptions)
return output
}
// vue.js
function parseComponent(content, options) {
// ...
var sfc = {
template: null,
script: null,
styles: [],
customBlocks: [] }
// ...
return sfc
}
我们可以将SFC结构融合到Webpack进行开发的过程成中, 主要有这几点影响:
允许为 Vue 组件的每个部分使用其它的 webpack loader,例如在 <style>的部分使用 Sass Loader , 在 <customBlocks>的部分使用自定义 Loader
使用 webpack loader 将 <style>和 <template> 中引用的资源当作模块依赖来处理










