js基础:WebComponents 和 ShadowDOM
WebComponents 和 ShadowDOM
组件化存在的问题
HTML 和 CSS 是如何阻碍前端组件化的,一个简单的例子:
1 2 3 4 5 6 7
| <style> p { background-color: brown; color: cornsilk; } </style> <p>I am river</p>
|
问题:
- CSS 是影响全局的
- 任何地方都可以直接读取和修改 DOM
WebComponent
WebComponent 给出了解决思路,它提供了对局部视图封装能力,可以让 DOM、CSSOM 和 JavaScript 运行在局部环境中,这样就使得局部的 CSS 和 DOM 不会影响到全局。
WebComponent 是一套技术的组合,具体涉及到了 Custom elements(自定义元素)、Shadow DOM(影子 DOM)和 HTML templates(HTML 模板)
影子 DOM
影子 DOM 的作用是将模板中的内容与全局 DOM 和 CSS 进行隔离,这样我们就可以实现元素和样式的私有化了。你可以把影子 DOM 看成是一个作用域,其内部的样式和元素是不会影响到全局的样式和元素的,而在全局环境下,要访问影子 DOM 内部的样式或者元素也是需要通过约定好的接口的。
实现例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| <!DOCTYPE html> <html> <body>
<template id="river-t"> <style> p { background-color: brown; color: cornsilk; }
div { width: 200px; background-color: bisque; border: 3px solid chocolate; border-radius: 10px; } </style> <div> <p>I am river</p> <p>I am river</p> </div> <script> function foo() { console.log('inner log') } </script> </template> <script> class River extends HTMLElement { constructor() { super() const content = document.querySelector('#river-t').content const shadowDOM = this.attachShadow({ mode: 'open' }) shadowDOM.appendChild(content.cloneNode(true)) } } customElements.define('river', River) </script>
<river></river> <div> <p>I am river</p> <p>I am river</p> </div> <river></river> </body> </html>
|
首先,使用 template 属性来创建模板。利用 DOM 可以查找到模板的内容,但是模板元素是不会被渲染到页面上的,也就是说 DOM 树中的 template 节点不会出现在布局树中,所以我们可以使用 template 来自定义一些基础的元素结构,这些基础的元素结构是可以被重复使用的。
其次,我们需要创建一个 River 的类。在该类的构造函数中要完成三件事:查找模板内容;创建影子 DOM;再将模板添加到影子 DOM 上。
最后,就很简单了,可以像正常使用 HTML 元素一样使用该元素,如上述代码中的。
以上
在没有 webcomponent 的时候,通过 react 和 vue 基于当前的前端特性去实现组件化,他们之间是互相影响和借鉴的,最终 react 和 vue 也会向 webcomponent 标准的方向演进。但是现在由于 webcomponent 的浏览器支持还不是太好,所以现阶段它们还是会并存的。Vue,React 是从开发者层面解决了组件化的问题,提高了效率。WebComponent 是从浏览器引擎实现层面解决了组件化的问题。
-
版权声明: 本博客所有文章除特别声明外,均采用
CC BY 4.0 CN协议
许可协议。转载请注明出处!
Жизнь, как качели - то вверх, то вниз.