深入探讨虚拟企业应用系统范围CSS的实现原理
用VueJS开发应用,离不开在应用之间拆分模块,把大接口拆解成组件的过程。我们可以轻松地使用模板块来维护组件的视图,脚本来维护组件的逻辑部分,样式来维护单个文件中组件的样式。我们在编写VueJS组件的风格时,一定要忽略风格污染。
风格污染的原因
说到风格污染,主要追溯到Webpack对CSS文件的打包过程。这里,我们以Vue-Element-Admin中的Webpack配置项为例:
const webpackConfig=merge(basebpackconfig,{ plugins :[new minissextractplugin({ filename : utils . asset path(' CSS/[name]))。[contenthash:8]。css '),区块文件名: utils。asset path(' CSS/[name])。[内容哈希:8]。CSS')}),]}) Web Pack使用MiniCssExtractPlugin插件,将文件(如Vue单文件组件)中的CSS代码处理后分离成app.hash1234.css的形式。
如果项目中存在大量同名的ClassName而没有添加防止风格污染的措施,可能会产生意想不到的CSS选择器权重覆盖,这可能会使后期文件中某些部分选择器权重较高的类影响整个应用程序,而这个过程通常发生在组件的编写中,所以一般称为组件风格污染。
网络包Vue SFC对象
对于Vue项目来说,使用Webpack会大大优化工作流程,因为VUE单文件组件可以通过Vue Loader很好地集成到Webpack工作流程中,Vue通过跟踪源代码可以发现,我们编写的单文件组件都被当作SFC对象,即包含单个HTML模块、单个脚本模块、一个或多个样式模块以及一个或多个自定义模块的对象:
//vue-loader/index . jsconst descriptor=parse({ source,compiler : Options.compiler | | loadtemplatecoiler()、filename、sourceRoot、needmap : source map })//vue js/component-compiler-utils/index . jsfunction parse(options) { const { compiler }=Options output=compiler . parseoptions(source,compiler parseoptions)return output }//vue . jsfunction parseComponent(content,Options){.var SFC={模板: null,脚本: null,样式3360 [],自定义块: []}//.return sfc}我们可以将sfc结构集成到Webpack的开发过程中,主要影响:
Vue组件的每个部分都允许使用其他网络打包器,例如样式部分中的Sass Loader和自定义块部分中的自定义加载器。样式和模板中引用的资源被视为模块依赖,以模拟Scoped CSS。热重载用于在开发过程中保持状态。下面主要介绍Scoped CSS的原理。
限定范围的CSS
本地版本的作用域CSS原则
通过Webpack调用VueJS中对应的Loader,将自定义的Attribute) data-v-x v-x添加到组件的HTML模板中,将对应的属性选择器[data-v-x]添加到组件中的CSS选择器中,达到组件中的样式只能生效,组件中的HTML不能生效的效果。代码效果如下:
div class=' lionad ' data-v-lionad/div style . lionad[data-v-lionad]{ background : @ tiger-orange;}/style源代码跟踪
在Webpack使用其他CSS Loader处理VueJS中对应的CSS代码之前,Vue Loader已经为我们做了一个简单的流程。如果组件中的样式块包含范围属性:
!-在VueJS组件中-模板div class=' lion ad '/div/模板stylelang=' scss '作用域。lion ad { background : @ tiger-orange;}/style下的代码判断当前SFC对象样式块中是否存在作用域属性,并将其插入查询。顺带一提,每个单个文件组件解析后,会生成对应的组件id,主要是由生产/开发环境区分,由文件路径的源代码或者文件路径的值作为hash特征值生成,如下图:所示
//vue-loader/index . jsconst id=hash(is production(short filepath ' \ n ' source): short filepath)const hasScoped=descriptor . style . some(s=s . scoped)const query=`?Vue类型=template $ { idquery } $ { scopedquery } ` const request=template request=stringify request(src query)模板导入=`import {render,staticrederfns }来自$ {request} `html模板处理
在SFC结构的处理HTML模板的templateLoader中,我们可以知道查询中设置的参数会合并到Loader选项中,通过Webpack传递给templateLoader,然后再传递给@ vue/component-compiler-utils.compiletemplate processing 3360。
//vue-loader/template loader . jsconst query=QS . parse(this . resource query)const { id }=queryconst compile options=object . assign({ },options.compilerOptions,{ scopeId: query.scoped?` data-v-$ { id } ` : null })Const compiled=compileTemplate({编译器选项})实际的compileTemplate函数在query或vue-template-compiler中使用编译器,将模板文本转换为JavaScript呈现函数,大致如下:
将HTML模板翻译成AST(虚拟语法树)AST优化,处理静态模板和动态模板生成JS函数,用于在运行时生成:对应的纯HTML代码。
//vue-template-compiler/build . js/createcompilerceretorvarast=parse(template . trim(),options)options)option(ast,options) varcode=generate (ast,options)以前,在解析阶段解析开始标记时,我们的组件ID被推送到内部存储的数据结构中。
function elementToOpenTagSegments(El,state){ var segments=[{ type : RAW,value :('(El . tag))}]//_ scopedId if(state . options . scope id){ segments . push({ type : RAW,value :('(state。options.scopeid))})}段。push ({type: raw,value:''})返回段}我们的HTML模板div class='lionad'/div中的开始标记将转换为以下数据结构:
[ { type: RAW,value: 'div' },{ type: RAW,value: 'class=lionad' },{ type: RAW,value: 'data-v-
版权声明:深入探讨虚拟企业应用系统范围CSS的实现原理是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。