这篇文章发布于 2021年02月13日,星期六,23:09,归类于 CSS相关, JS实例。 阅读 16060 次, 今日 1 次 6 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9816
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
为了重复利用,本文的Web Components组件就使用前两天写的“巧用两个type=range input实现区域范围选择”这篇文章中的Range组件示意。
原Range组件的CSS都是直接内联在Shadow DOM中的,如下图所示:
实际开发时候,往往会碰到需要引入外部CSS到Shadow DOM中的情况,此时该如何处理才合适呢?
本文介绍3种处理方法。
假设Range组件需要的CSS都放在了一个名为range.css的文件中。
一、@import方法
代码示意:
class uiRange extends HTMLElement { constructor () { super(); // 附加Shadow DOM this.attachShadow({ mode: 'open' }); // 创建样式 let node = document.createElement('style'); node.innerHTML = `@import './range.css';`; this.shadowRoot.append(node); } ... } if (!customElements.get('ui-range')) { customElements.define('ui-range', uiRange); }
引用的核心就是下面这样CSS语句:
@import './range.css'
实际DOM渲染效果如下截图(截自Firefox):
优缺点
优点是兼容性不错,支持Shadow DOM的元素均支持此语法;以及使用比较方便。
缺点是性能著名的差。根据我看到的某些资料的测试数据,会有半秒左右的阻塞。
不过有些站点对于小小的阻塞延时并不在意,反而更在意使用的便捷性,此时使用@import也是可以的,比方说一些demo原型页面,内部的文档页面等。
如果对性能比较在意,可以试试下面的fetch方法。
二、fetch获取
直接以请求的方式去load CSS文件的资源内容,并在Shadow DOM中输出。
代码示意:
class uiRange extends HTMLElement { constructor () { super(); // 附加Shadow DOM this.attachShadow({ mode: 'open' }); // 获取样式 fetch('./range.css').then(response => response.text()).then(data => { let node = document.createElement('style'); node.innerHTML = data; this.shadowRoot.appendChild(node); }); } ... } if (!customElements.get('ui-range')) { customElements.define('ui-range', uiRange); }
由于fetch执行的时候是个异步的过程,因此并不会发生加载阻塞,理论性能会好一点。
优缺点
优点是兼容性不错,支持Shadow DOM的元素均支持此语法;以及性能还OK。
缺点是使用的时候比较啰嗦,也就是语句较多,以及感觉不是很正统。
//zxx: 如果你看到这段文字,说明你现在访问是体验糟糕的垃圾盗版网站,你可以访问原文获得很好的体验:https://www.zhangxinxu.com/wordpress/?p=9816(作者张鑫旭)
如果从正统角度来说的话,下面的方法是最合适,也是理论上应该推崇的外部CSS引入方法。
三、作为CSS module import
此方法使用浏览器原生的import语法,但是import的是CSS文件而不是JS文件。
也就是把CSS文件直接作为模块引入。
相关代码演示如下:
import styles from './range.css'; class uiRange extends HTMLElement { constructor () { super(); let shadow = this.attachShadow({ mode: 'open' }); shadow.adoptedStyleSheets = [styles]; } ... } if (!customElements.get('ui-range')) { customElements.define('ui-range', uiRange); }
简单的2步:
- import引入;
- adoptedStyleSheets采用;
这个方法是本文介绍重点,因此有demo,您可以狠狠地点击这里:Web Components中CSS样式import引用demo
说明:由于CSS文件直接import这个语法目前仅Chrome及其同样内核浏览器支持,因此Firefox和Safari下使用的是fetch方法。
关于adoptedStyleSheets
adoptedStyleSheets
这个API方法是随着样式表构造(Constructed StyleSheets)一起出现的。
存在与shadowRoot和document两个对象上,用来设置样式。
例如:
document.adoptedStyleSheets; // 默认返回 []
adoptedStyleSheets
牵扯到的新的知识点很多,这里不具体展开,以后有机会更详细介绍。
优缺点
优点是使用方便快捷且是官方推荐方法,或者是import CSS模块就是为了这个场景才支持的;以及性能OK,import本身就是异步过程。
缺点就是兼容性不行,如下图(数据源自MDN文档),Firefox和Safari还没有支持。
目前使用还不太成熟,不过现在浏览器支持新特性都是很快的。
说不定2年后就可以用起来了。
其实,配合一些打包工具,实际项目中也是可以使用的。
四、3个方法对比总结
最后,把本文介绍的3个方法再一起对比总结下,参见下表:
性能好 | 使用便捷 | 兼容性好 | |
---|---|---|---|
@import | ✘ | ✔ | ✔ |
fetch | ✔ | ✘ | ✔ |
import | ✔ | ✔ | ✘ |
可以发现,缺点每个方法各占一项。
其中,import方法未来最有潜力,因为,兼容性可以慢慢变好,而其他两个方法的缺点已经定型没救了。
大家可以根据实际使用场景选择合适的方法。
以上就是正文内容,感谢你的阅读,行为仓促,如有错误,欢迎指正。
如果觉得文章不错,也欢迎分享。
看到上面爱心图标突然想到明天是情人节,哎呀,突然脑壳疼~~
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9816
(本篇完)
- 万岁,浏览器原生支持ES6 export和import模块啦! (0.541)
- 使用jsPDF导出PDF文件实践分享 (0.497)
- polyfill、ponyfill、prollyfill傻傻分不清楚 (0.344)
- HTMLUnknownElement与HTML5自定义元素的故事 (0.306)
- 使用::part伪元素改变Shadow DOM的CSS样式 (0.306)
- 巧用两个type=range input实现区域范围选择 (0.306)
- 如何继承自定义元素及其他JS中扩展新方法 (0.306)
- 博闻强识:了解CSS中的@ AT规则 (0.197)
- JS一般般的网页重构可以使用Node.js做些什么 (0.197)
- HTML静态页面原型交付工具“魔卡”简介 (0.197)
- Safari不支持build-in自定义元素的兼容处理 (RANDOM - 0.153)
其实还可以通过属性从外部覆盖
你那个最后的“import引用”Demo无法执行。控制台报了”Failed to load module script: The server responded with a non-JavaScript MIME type of “text/css”. Strict MIME type checking is enforced for module scripts per HTML spec.”错误。
需要服务器端设置MIME为application/javascript.
在 (二、fetch获取 )的讲解中, fetch的回调里有一句(shadow.appendChild(node))。 其中shadow是不是没有定义? 还是我理解有问题,shadow在上下文中本来就有?
感谢反馈,这里应该是this.shadowRoot。
从工程上来看,可以直接把css文件当做文本来import,实际上就是作为文本进行插入了
打包工具应该可以做这样的事情