持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
随着前端技术的不断发展,“模块化”的概念在前端领域愈发重要,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
<!--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>
使用它
<!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(可选):配置对象
需要说明的是,第二个参数里的类有两种类型
- 继承 HTMLElement,使用时可以独立使用
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,使用需要结合原生标签使用
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文件中,具体使用方式如下
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);