随着前端技术的不断发展,“模块化”的概念在前端领域愈发重要,es6提出的esm,以及更早的cjs,amd,cmd等等,都是围绕前端模块化提出的,并且现在流行的三大前端框架:vue、react、angular,都是基于模块化的方式进行开发
由此可见“模块化”的重要性,因此浏览器也提出了原生的模块化方案,即 web-components,它让我们可以自定义html标签并复用自定义内容,废话不多说,下面就详细聊聊它吧
什么是web-components
web-components 是一组 Web 平台 API
,建立在 Web 标准之上,它允许开发人员创建新的自定义
、可重用
、被封装
的 HTML 标记
在网页和 Web 应用程序中使用
web-components是一种技术体系规范,该体系下主要涉及了如下四种技术
- HTML Imports
- Custom Elements
- Shadow DOM
- HTML templates
下面来依次讲解它们
HTML Imports
HTML imports
提供了一种在一个 HTML中包含和重用另一个 HTML 的方法,下面给一个例子
定义一个可重用的html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <!--test.html --> <template> <div>hello world</div> </template> <script> const dom = document.currentScript.ownerDocument.querySelector('template').content; class Test extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }).appendChild(dom); } } // 注册组件 customElements.define('test', Test); </script> <style> div { font-weight:bold; } </style>
|
使用它
1 2 3 4 5 6 7 8 9 10 11
| <!DOCTYPE html> <html lang="en"> <head> <title>Web Components</title> <!-- HTML Imports --> <link rel="import" href="test.html"> </head> <body> <test></test> </body> </html>
|
需要注意的是由于 HTML Imports 已经废弃,我在最新的谷歌浏览器(版本 106.0.5249.119)上进行了测试,模板导入没有任何效果,所以不推荐使用此方式
Custom Elements
这种方式给了我们开发者自定义html标签的能力,通过将自定义的内容封装在我们的自定义标签内,可以很方便地实现模板内容的复用
它主要是通过 customElements.define(name, constructor, options)
来实现的,三个参数的含义如下
- name:表示创建的元素名称,不能是单个单词,必须要有短横线
- constructor:定义元素的类
- options(可选):配置对象
需要说明的是,第二个参数里的类有两种类型
1 2 3 4 5 6 7 8 9 10 11
| class MyComp extends HTMLElement { constructor() { super(); let template = document.getElementById('template'); let templateContent = template.content; const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true)); } } customElements.define('my-comp', MyComp);
使用:<my-comp></my-comp>
|
- 继承 HTMLParagraphElement,使用需要结合原生标签使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MyComp extends HTMLParagraphElement { constructor() { super(); let template = document.getElementById('template'); let templateContent = template.content; const shadowRoot = this.attachShadow({mode: 'open'}) .appendChild(templateContent.cloneNode(true)); } } customElements.define('my-comp', MyComp, { extends: 'p' });
使用:<p is="my-comp"></p>
|
Shadow DOM
web-components的封装能力, Shadow DOM是最关键的一环,Shadow DOM 可以将 标记结构、样式 和 行为 隐藏起来,并与页面上的其他代码相隔离,可以看作是创建了一个沙箱环境,内部和外部都不会互相影响
其实很多原生标签就是浏览器里由shadow-dom来实现的,比如:video、audio,可以通过浏览器的开发工具进行查看
HTML templates
template 是web-components提供的一个标签,它的特性就是包裹在 template 中的 HTML 片段 不会 在页面加载的时候解析渲染,但是可以被js访问到并进行操作,我们可以通过它来定义自定义标签的结构、样式与行为
由于 HTML Imports 特性被废弃,因此目前定义模板的方式是将其放入js文件中,具体使用方式如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const template = document.createElement('template');
template.innerHTML = ` <style> span{ color:red } </style> <span id='text'>Hello WebComponent</span> ` class MyComp extends HTMLElement { constructor() { super(); let templateContent = template.content.cloneNode(true); const shadow = this.attachShadow({mode: 'open'}) templateContent.querySelector("#text").addEventListener('click',()=>{ alert('test') }) shadow.appendChild(templateContent); } } customElements.define('my-comp', MyComp);
|