Web Component 有点东西
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 web 应用中使用它们。–MDN
简单来讲就是浏览器提供的原生组件复用方案。主要由三种技术方案实现:
Custom elements(自定义元素)。可以用来定义标签(元素)
Shadow DOM(影子 DOM)。可以用来做样式隔离
HTML templates(HTML 模板)。可以用来定义一个基础的组件的dom结构
实现 Web Component 的最基本流程:
template来定义一个_组件_的dom<template id="mHeader">
<div>
<span class="content" id="content">我是头部</span>
</div>
</template>
template创建一个_类组件_class MHeader extends HTMLElement {
constructor() {
super();
// attachShadow() 方法来将一个 shadow root 附加到任何一个元素上,该方法返回一个 shadow root 。
const shadowRoot = this.attachShadow({ mode: "closed" });
const template = document.querySelector("#mHeader");
const content = template.content.cloneNode(true);
shadowRoot.appendChild(content);
}
}
/**
* 注意,组件名是有限制的,MHeader、header1等都是不能用的,浏览器会报错
*
* web-component.html:33 Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': "header1" is not a valid custom element name
at file:///Users/echo/Desktop/web-component.html:33:27
*/
window.customElements.define("m-header", MHeader);
<!-- 使用的地方没有限制,自闭合也是可以的 -->
<m-header />
可以直接在template里添加style标签,在里面可以添加只在该template下生效的样式
:host选择器可以选择组件的根元素
<template id="mHeader">
<style> :host {
font-size: 32px;
}
.content {
color: #f00;
} </style>
<div>
<span class="content" id="content">我是头部</span>
</div>
</template>
需要在第 2 步在定义组件时用到this.getAttribute来获取传入的属性
class MHeader extends HTMLElement {
constructor() {
// ...
const title = this.getAttribute("title");
if (title) {
content.querySelector("#content").innerText = title;
}
// ...
}
}
<m-header title="hello" />;
可以使用querySelector获取到template内部的一些元素来添加事件
<template id="mHeader">
<div>
<!-- ... -->
<button id="login">login</button>
</div>
</template>
接着绑定事件
class MHeader extends HTMLElement {
constructor() {
// ...
content.querySelector("#login").addEventListener("click", () => {
alert("login");
});
// ...
}
}
通过CustomEvent来进行通信
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<template id="mHeader">
<style> :host {
font-size: 32px;
}
.content {
color: #f00;
} </style>
<div>
<span class="content" id="content">我是头部</span>
<button id="login">login</button>
</div>
</template>
<m-header id="mHeader" title="hello" />
<script> class MHeader extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "closed" });
const template = document.querySelector("#mHeader");
const content = template.content.cloneNode(true);
const title = this.getAttribute("title");
if (title) {
content.querySelector("#content").innerText = title;
}
const myEvent = new CustomEvent("login", {
detail: "这是子组件传过来的消息",
});
const loginBtn = content.querySelector("#login");
loginBtn.addEventListener("click", () => {
alert("login");
});
shadowRoot.appendChild(content);
}
}
window.customElements.define("m-header", MHeader); </script>
</body>
</html>
未完待续
to be continued…
GitHub。GitHub是基于 Web Components 来开发的

其次,Vue.js和微信小程序也是基于 Web Components 来做组件化的
Web Component 是浏览器提供的可以用于组件复用的方案,可以实现样式隔离,自定义属性、父子组件通信等功能,但书写起来有些不够便捷,需要用到原生 dom 操作 api