Web Components 实例

简介

由 4 门技术结合起来的

  • HTML Imports –> HTML Modules
  • HTML Templates
  • Custom Elements
  • Shadow DOM

成熟的组件库特点:

  • 随处复用
  • 风格统一
  • 动效自然

实例

来看一组下面的实例,讲述了如何定义 web components 并获取 iframe 中的 web components

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
56
<!-- index.html -->
<!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>
<h1>开启服务才能获取 iframe 内容</h1>
<iframe src="./iframe.html"></iframe>
<fs-components></fs-components>
<script>
customElements.define(
"fs-components",
class extends HTMLElement {
constructor() {
super();
// 相当于 Vue 的 setup
console.log("先运行构造函数");
}
connectedCallback() {
// 相当于 Vue 的 mounted
console.log("再运行连接回调");
}
disconnectedCallback() {
// 相当于 Vue 的 unmounted
console.log("当删除组件时才会运行失联回调");
}
adoptedCallback() {
document.adoptNode();
alert("被导入");
// document.adoptNode 从外部文档导入节点,剪切式 (有跨域限制🚫)
// 当使用 document.adoptNode 后会触发该生命周期
console.log("当使用 document.adoptNode 后会运行收养回调");
}
attributeChangedCallback(name, oldValue, newValue) {
// 相当于 Vue 的 watch, 属性变化时回调
}
}
);

const iframe = document.querySelector("iframe");
// 对自身网页使用不触发
const selfComponent = document.querySelector("fs-components");
document.body.appendChild(document.adoptNode(selfComponent));
// 获取iframe中的web-component
iframe.onload = () => {
const webComponent =
iframe.contentDocument.querySelector("fancy-components");
document.body.appendChild(document.adoptNode(webComponent));
};
</script>
</body>
</html>
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
<!-- iframe.html -->
<!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>If</title>
</head>
<body>
<fancy-components></fancy-components>
<script>
customElements.define(
"fancy-components",
class extends HTMLElement {
constructor() {
super();
// 相当于 Vue 的 setup
console.log("先运行构造函数");
}
connectedCallback() {
// 相当于 Vue 的 mounted
console.log("再运行连接回调");
}
disconnectedCallback() {
// 相当于 Vue 的 unmounted
console.log("当删除组件时才会运行失联回调");
}
adoptedCallback() {
alert("iframe内 fancy-components 被导入");
// document.adoptNode 有跨域限制🚫
// 当使用 document.adoptNode 后会触发该生命周期
console.log("当使用 document.adoptNode 后会运行收养回调");
}
}
);
</script>
</body>
</html>

也可以继承 HTML 元素

1
2
3
4
5
6
7
8
9
10
11
12
13
customElements.define(
"our-input",
class extends HTMLInputElement {
constructor() {
super();

this.placeholder = "属于我们的输入框!";
this.disabled = true;
}
// 拓展 HTMLInputElement 的子类
},
{ extends: "input" }
);

相信从以上案例,已经能初步了解 web components 的用法,更多用途在网络上有更丰富的案例

组件库

CSS-Doodle

基于 web components 开发的组件库,(炫酷效果的组件库,日常开发中用不到)
css-doodle

fancy-components

花式组件库, 在日常开发中用得到
fancy-components

在框架中使用

React 支持 WebComponents

只要首字母不大写,大写是组件, 小写就是标签

1
2
3
<fc-button>
<TextView />
</fc-button>

Vue 中支持 WebCompents

在 vue.config.js 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
chainWebpack: (config) => {
config.module
.rule("vue")
.use("vue-loader")
.tap((options) => {
// 编译忽略某个标签名
options.compilerOptions = {
...(options.compilerOptions || {}),
isCustomElement: (tag) => tag.startsWith("fc-"),
};

return options;
});
},
};

vite 中使用 WebCompents

在 vite.config.js 中

1
2
3
4
5
6
7
8
9
10
11
12
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith("fc-"),
},
},
}),
],
});
作者

Huasun47

发布于

2021-06-19

更新于

2021-06-19

许可协议