CSS Scoped的实现原理是什么


本文小编为大家详细介绍“CSS Scoped的实现原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“CSS Scoped的实现原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。CSS Scoped的实现原理
在Vue单文件组件中,我们只需要在style标签上加上scoped属性,就可以实现标签内的样式在当前模板输出的HTML标签上生效,其实现原理如下每个Vue文件都将对应一个唯一的id,该id可以根据文件路径名和内容hash生成编译template标签时时为每个标签添加了当前组件的id,如编译style标签时,会根据当前组件的id通过属性选择器和组合选择器输出样式,如.demo{color: red;}会被编译成.demo[data-v-27e4e96e]{color: red;}了解了大致原理,可以想到css scoped应该需要同时处理template和style的内容,现在归纳需要探寻的问题渲染的HTML标签上的data-v-xxx属性是如何生成的CSS代码中的添加的属性选择器是如何实现的resourceQuery
在此之前,需要了解首一下webpack中Rules.resourceQuery的作用。在配置loader时,大部分时候我们只需要通过test匹配文件类型即可resourceQuery提供了根据引入文件路径参数的形式匹配路径vue-loader中就是通过resourceQuery并拼接不同的query参数,将各个标签分配给对应的loader进行处理。
loader.pitch
参考pitching-loader官方文档
webpack的pitching loaderwebpack中loaders的执行顺序是从右到左执行的,如loaders:[a, b, c],loader的执行顺序是c->b->a,且下一个loader接收到的是上一个loader的返回值,这个过程跟”事件冒泡”很像。
但是在某些场景下,我们可能希望在”捕获”阶段就执行loader的一些方法,因此webpack提供了loader.pitch的接口。
一个文件被多个loader处理的真实执行流程,如下所示
loader和pitch的接口定义大概如下所示
正常情况下,一个loader在execution阶段会返回经过处理后的文件文本内容。如果在pitch方法中直接返回了内容,则webpack会视为后面的loader已经执行完毕(包括pitch和execution阶段)。
在上面的例子中,如果b.pitch返回了result b,则不再执行c,则是直接将result b传给了a。
VueLoaderPlugin
接下来看看与vue-loader配套的插件:VueLoaderPlugin,该插件的作用是:将在webpack.config定义过的其它规则复制并应用到 .vue 文件里相应语言的块中。其大致工作流程如下所示获取项目webpack配置的rules项,然后复制rules,为携带了?vue&lang=xx…query参数的文件依赖配置xx后缀文件同样的loader为Vue文件配置一个公共的loader:pitcher将[pitchLoder, …clonedRules, …rules]作为webapck新的rules因此,为vue单文件组件中每个标签执行的lang属性,也可以应用在webpack配置同样后缀的rule。这种设计就可以保证在不侵入vue-loader的情况下,为每个标签配置独立的loader,如可以使用pug编写template,然后配置pug-plain-loader可以使用scss或less编写style,然后配置相关预处理器loader可见在VueLoaderPlugin主要做的两件事,一个是注册公共的pitcher,一个是复制webpack的rules。
vue-loader
接下来我们看看vue-loader做的事情。
pitcher
前面提到在VueLoaderPlugin中,该loader在pitch中会根据query.type注入处理对应标签的loader当type为style时,在css-loader后插入stylePostLoader,保证stylePostLoader在execution阶段先执行当type为template时,插入templateLoader由于loader.pitch会先于loader,在捕获阶段执行,因此主要进行上面的准备工作:检查query.type并直接调用相关的loadertype=style,执行stylePostLoadertype=template,执行templateLoader这两个loader的具体作用我们后面再研究。
vueLoader
接下来看看vue-loader里面做的工作,当引入一个x.vue文件时
处理template标签,拼接type=template等query参数
处理script标签
处理style标签,为每个标签拼接type=style等参数
可见在vue-loader中,主要是将整个文件按照标签拼接对应的query路径,然后交给webpack按顺序调用相关的loader。
templ 香港云主机ateLoader
回到开头提到的第一个问题:当前组件中,渲染出来的每个HTML标签中的hash属性是如何生成的。
我们知道,一个组件的render方法返回的VNode,描述了组件对应的HTML标签和结构,HTML标签对应的DOM节点是从虚拟DOM节点构建的,一个Vnode包含了渲染DOM节点需要的基本属性。
那么,我们只需要了解到vnode上组件文件的哈希id的赋值过程,后面的问题就迎刃而解了。
关于compileTemplate的实现,我们不用去关心其细节,其内部主要是调用了配置参数compiler的编译方法
在Vue源码中可以了解到,template属性会通过compileToFunctions编译成render方法;在vue-loader中,这一步是可以通过vue-template-compiler提前在打包阶段处理的。
vue-template-compiler是随着Vue源码一起发布的一个包,当二者同时使用时,需要保证他们的版本号一致,否则会提示错误。这样,compiler.compile实际上是Vue源码中vue/src/compiler/index.js的baseCompile方法,追着源码一致翻下去,可以发现
以前面的至此,我们知道了在templateLoader中,会根据单文件组件的id,拼接一个scopeId,并作为compilerOptions传入编译器中,被解析成vnode的配置属性,然后在render函数执行时调用createElement,作为vnode的原始属性,渲染成到DOM节点上。
stylePostLoader
在stylePostLoader中,需要做的工作就是将所有选择器都增加一个属性选择器的组合限制,我们需要了解compileStyle的逻辑
最后让我们在了解一下scopedPlugin的实现,
由于我对于PostCSS的插件开发并不是很熟悉,这里只能大致整理,翻翻文档了,相关API可以参考Writing a PostCSS Plugin。
至此,我们就知道了第二个问题的答案:通过selector.insertAfter为当前styles下的每一个选择器添加了属性选择器,其值即为传入的scopeId。由于只有当前组件渲染的DOM节点上上面存在相同的属性,从而就实现了css scoped的效果。
小结
回过头来整理一下vue-loader的工作流程首先需要在webpack配置中注册VueLoaderPlugin在插件中,会复制当前项目webpack配置中的rules项,当资源路径包含query.lang时通过resourceQuery匹配相同的rules并执行对应loader时插入一个公共的loader,并在pitch阶段根据query.type插入对应的自定义loader准备工作完成后,当加载*.vue时会调用vue-loader,一个单页面组件文件会被解析成一个descriptor对象,包含template、script、styles等属性对应各个标签,对于每个标签,会根据标签属性拼接src?vue&query引用代码,其中src为单页面组件路径,query为一些特性的参数,比较重要的有lang、type和scoped如果包含lang属性,会匹配与该后缀相同的rules并应用对应的loaders根据type执行对应的自定义loader,template将执行templateLoader、style将执行stylePostLoader在templateLoader中,会通过vue-template-compiler将template转换为render函数,在此过程中,会将传入的scopeId追加到每个标签的segments上,最后作为vnode的配置属性传递给createElemenet方法,在render函数调用并渲染页面时,会将scopeId属性作为原始属性渲染到页面上在stylePostLoader中,通过PostCSS解析style标签内容,同时通过scopedPlugin为每个选择器追加一个[scopeId]的属性选择器由于需要Vue源码方面的支持(vue-template-compiler编译器),CSS Scoped可以算作为Vue定制的一个处理原生CSS全局作用域的解决方案。除了 css scoped之外,vue还支持css module,我打算在下一篇整理React中编写CSS的博客中一并对比整理。
读到这里,这篇“CSS Scoped的实现原理是什么”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注开发云行业资讯频道。推荐内容:CSS Scoped的实现原理分析免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@if98.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

相关推荐: vue.js中如何全局调用MessageBox组件

这篇文章主要介绍“vue.js中如何全局调用MessageBox组件”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue.js中如何全局调用MessageBox组件”文章能帮助大家解决问题。组件模板{{content}…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 07/16 17:32
下一篇 07/16 17:32

相关推荐