Skip to content

Commit b387918

Browse files
committed
docs: edit web components
1 parent bb97fbd commit b387918

File tree

1 file changed

+125
-83
lines changed

1 file changed

+125
-83
lines changed

docs/webcomponents.md

Lines changed: 125 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,122 +2,68 @@
22

33
## 概述
44

5-
各种网站往往需要一些相同的模块,比如日历、调色板等等,这种模块就被称为“组件”(component)。Web Components 就是网页组件式开发的技术规范
5+
各种网站往往需要一些相同的模块,比如日历、调色板等等,这种模块就被称为“组件”(component)。Web Components 就是浏览器原生的组件规范
66

7-
采用组件进行网站开发,有很多优点。
7+
采用组件开发,有很多优点。
88

9-
(1)管理和使用非常容易。加载或卸载组件,只要添加或删除一行代码就可以了。
9+
(1)有利于代码复用。组件是模块化编程思想的体现,可以跨平台、跨框架使用,构建、部署和与其他 UI 元素互动都有统一做法。
10+
11+
(2)使用非常容易。加载或卸载组件,只要添加或删除一行代码就可以了。
1012

1113
```html
1214
<link rel="import" href="my-dialog.htm">
1315
<my-dialog heading="A Dialog">Lorem ipsum</my-dialog>
1416
```
1517

16-
上面代码加载了一个对话框组件。
17-
18-
(2)定制非常容易。组件往往留出接口,供使用者设置常见属性,比如上面代码的heading属性,就是用来设置对话框的标题。
19-
20-
(3)组件是模块化编程思想的体现,非常有利于代码的重用。标准格式的模块,可以跨平台、跨框架使用,构建、部署和与其他UI元素互动都有统一做法。
21-
22-
(4)组件提供了HTML、CSS、JavaScript封装的方法,实现了与同一页面上其他代码的隔离。
23-
24-
未来的网站开发,可以像搭积木一样,把组件合在一起,就组成了一个网站。这是非常诱人的。
25-
26-
Web Components 不是单一的规范,而是一系列的技术组成,包括Template、Custom Element、Shadow DOM、HTML Import四种技术规范。使用时,并不一定这四者都要用到。其中,Custom Element和Shadow DOM最重要,Template和HTML Import只起到辅助作用。
27-
28-
## `<template>`标签
29-
30-
### 基本用法
31-
32-
`<template>`标签表示组件的 HTML 代码模板。
33-
34-
```html
35-
<template>
36-
<h1>This won't display!</h1>
37-
<script>alert("this won't alert!");</script>
38-
</template>
39-
```
40-
41-
`<template>`内部就是正常的 HTML 代码,浏览器不会将这些代码加入 DOM。
42-
43-
下面的代码会将模板内部的代码插入 DOM。
44-
45-
```javascript
46-
let template = document.querySelector('template');
47-
document.body.appendChild(template.content);
48-
```
49-
50-
注意,模板内部的代码只能插入一次,如果第二次执行上面的代码就会报错。
51-
52-
如果需要多次插入模板,可以复制`<template>`内部代码,然后再插入。
53-
54-
```javascript
55-
document.body.appendChild(template.content.cloneNode(true));
56-
```
57-
58-
上面代码中,`cloneNode()`方法的参数`true`表示复制包含所有子节点。
59-
60-
接受`<template>`插入的元素,叫做宿主元素(host)。在`<template>`之中,可以对宿主元素设置样式。
61-
62-
```html
63-
<template>
64-
<style>
65-
:host {
66-
background: #f8f8f8;
67-
}
68-
:host(:hover) {
69-
background: #ccc;
70-
}
71-
</style>
72-
</template>
73-
```
18+
上面代码中,第一行加载了一个对话框组件,第二行在网页上放置这个组件的实例。
7419

75-
### document.importNode()
20+
(3)开发和定制很方便。组件开发不需要使用框架,只要用原生的语法就可以了。开发好的组件往往留出接口,供使用者设置常见属性,比如上面代码的`heading`属性,就是用来设置对话框的标题。
7621

77-
document.importNode方法用于克隆外部文档的DOM节点
22+
(4)组件提供了 HTML、CSS、JavaScript 封装的方法,实现了与同一页面上其他代码的隔离
7823

79-
```javascript
80-
var iframe = document.getElementsByTagName("iframe")[0];
81-
var oldNode = iframe.contentWindow.document.getElementById("myNode");
82-
var newNode = document.importNode(oldNode, true);
83-
document.getElementById("container").appendChild(newNode);
84-
```
24+
未来的网站开发,可以像搭积木一样,把组件合在一起,就组成了一个网站。这种前景是非常诱人的。
8525

86-
上面例子是将iframe窗口之中的节点oldNode,克隆进入当前文档
26+
Web Components 不是单一的规范,而是一系列的技术组成,以下是它的四个构成
8727

88-
注意,克隆节点之后,还必须用appendChild方法将其加入当前文档,否则不会显示。换个角度说,这意味着插入外部文档节点之前,必须用document.importNode方法先将这个节点准备好。
28+
- Custom Elements
29+
- Template
30+
- Shadow DOM
31+
- HTML Import
8932

90-
document.importNode方法接受两个参数,第一个参数是外部文档的DOM节点,第二个参数是一个布尔值,表示是否连同子节点一起克隆,默认为false。大多数情况下,必须显式地将第二个参数设为true
33+
使用时,并不一定上面四种 API 都要用到。其中,Custom Element 和 Shadow DOM 比较重要,Template 和 HTML Import 只起到辅助作用
9134

9235
## Custom Element
9336

94-
HTML 预定义的网页元素,有时并不符合我们的需要,这时可以自定义网页元素,这就叫做 Custom Element。它是 Web component 技术的核心。举例来说,你可以自定义一个叫做`<super-button>`的网页元素。
37+
HTML 预定义的网页元素,有时并不符合我们的需要,这时可以自定义网页元素,这就叫做 Custom Element。简单说,它就是用户自定义的网页元素,是 Web components 技术的核心。
38+
39+
举例来说,你可以自定义一个叫做`<super-button>`的网页元素。
9540

9641
```html
97-
<super-button></super-button>
42+
<my-element></my-element>
9843
```
9944

100-
注意,自定义网页元素的标签名必须含有连字符`-`一个或多个都可。这是因为浏览器内置的的 HTML 元素标签名,都不含有连字符,这样可以做到有效区分。
45+
注意,自定义网页元素的标签名必须含有连字符`-`一个或多个连字符都可以。这是因为浏览器内置的的 HTML 元素标签名,都不含有连字符,这样可以做到有效区分。
10146

10247
下面的代码先定义一个自定义元素的类。
10348

10449
```javascript
10550
class MyElement extends HTMLElement {}
10651
```
10752

108-
然后,需要登记一下自定义元素与这个类之间的映射
53+
然后,`window.customElements.define()`方法,用来登记自定义元素与这个类之间的映射
10954

11055
```javascript
111-
customElements.define('my-element', MyElement);
56+
window.customElements.define('my-element', MyElement);
11257
```
11358

114-
登记以后,页面上的每一个`<my-element>`元素都是一个`MyElement`的实例。只要浏览器解析到`<my-element>`元素,就会运行`MyElement`的构造函数。
59+
登记以后,页面上的每一个`<my-element>`元素都是一个`MyElement`类的实例。只要浏览器解析到`<my-element>`元素,就会运行`MyElement`的构造函数。
11560

116-
自定义元素的类有一些自定义的生命周期方法
61+
自定义元素的类(`MyElement`)有一些自定义的生命周期方法
11762

118-
- `connectedCallback()`:自定义元素添加到页面时调用。这可能不止一次发生,比如元素被移除并重新添加。
119-
- `disconnectedCallback()`:自定义元素移除出页面时调用。
120-
- `attributeChangeCallback()`:修改白名单里面的自定义元素属性时触发。
63+
- `connectedCallback()`:自定义元素添加到页面(进入 DOM 树)时调用。这可能不止一次发生,比如元素被移除后又重新添加。类的设置应该尽量放到这个方法里面执行,因为这时各种属性和子元素都可用。
64+
- `disconnectedCallback()`:自定义元素移出 DOM 时执行。
65+
- `adoptedCallback()``document.adoptNode(element)`时执行。
66+
- `attributeChangeCallback()`:加入`observedAttributes`白名单的属性发生属性值变化时触发。
12167

12268
下面是一个例子。
12369

@@ -153,6 +99,25 @@ customElements.define('hey-there', GreetingElement);
15399
<hey-there name="Potch">Personalized Greeting</hey-there>
154100
```
155101

102+
生命周期方法调用的顺序如下:`constructor` -> `attributeChangedCallback` -> `connectedCallback`
103+
104+
```javascript
105+
class MyElement extends HTMLElement {
106+
constructor() {
107+
this.container = this.shadowRoot.querySelector('#container');
108+
}
109+
attributeChangedCallback(attr, oldVal, newVal) {
110+
if(attr === 'disabled') {
111+
if(this.hasAttribute('disabled') {
112+
this.container.style.background = '#808080';
113+
} else {
114+
this.container.style.background = '#ffffff';
115+
}
116+
}
117+
}
118+
}
119+
```
120+
156121
如果你想扩展现有的 HTML 元素(比如`<button>`)也是可以的。
157122
158123
```javascript
@@ -171,9 +136,21 @@ customElements.define('hey-there', GreetingElement, { extends: 'button' });
171136
<button is="hey-there" name="World">Howdy</button>
172137
```
173138
139+
除了直接插入网页,使用脚本插入网页也是可以的。
140+
141+
```javascript
142+
window.customElements.define(
143+
'my-element',
144+
class extends HTMLElement {...}
145+
);
146+
const el = window.customElements.get('my-element');
147+
const myElement = new el(); // same as document.createElement('my-element');
148+
document.body.appendChild(myElement);
149+
```
150+
174151
### document.registerElement()
175152
176-
使用自定义元素前,必须用document对象的registerElement方法登记该元素。该方法返回一个自定义元素的构造函数。
153+
使用自定义元素前,必须用`document.registerElement()`方法登记该元素。该方法返回一个自定义元素的构造函数。
177154
178155
```javascript
179156
var SuperButton = document.registerElement('super-button');
@@ -341,6 +318,70 @@ var XFoo = document.registerElement('x-foo-with-markup',
341318
342319
```
343320
321+
## `<template>`标签
322+
323+
### 基本用法
324+
325+
`<template>`标签表示组件的 HTML 代码模板。
326+
327+
```html
328+
<template>
329+
<h1>This won't display!</h1>
330+
<script>alert("this won't alert!");</script>
331+
</template>
332+
```
333+
334+
`<template>`内部就是正常的 HTML 代码,浏览器不会将这些代码加入 DOM。
335+
336+
下面的代码会将模板内部的代码插入 DOM。
337+
338+
```javascript
339+
let template = document.querySelector('template');
340+
document.body.appendChild(template.content);
341+
```
342+
343+
注意,模板内部的代码只能插入一次,如果第二次执行上面的代码就会报错。
344+
345+
如果需要多次插入模板,可以复制`<template>`内部代码,然后再插入。
346+
347+
```javascript
348+
document.body.appendChild(template.content.cloneNode(true));
349+
```
350+
351+
上面代码中,`cloneNode()`方法的参数`true`表示复制包含所有子节点。
352+
353+
接受`<template>`插入的元素,叫做宿主元素(host)。在`<template>`之中,可以对宿主元素设置样式。
354+
355+
```html
356+
<template>
357+
<style>
358+
:host {
359+
background: #f8f8f8;
360+
}
361+
:host(:hover) {
362+
background: #ccc;
363+
}
364+
</style>
365+
</template>
366+
```
367+
368+
### document.importNode()
369+
370+
document.importNode方法用于克隆外部文档的DOM节点。
371+
372+
```javascript
373+
var iframe = document.getElementsByTagName("iframe")[0];
374+
var oldNode = iframe.contentWindow.document.getElementById("myNode");
375+
var newNode = document.importNode(oldNode, true);
376+
document.getElementById("container").appendChild(newNode);
377+
```
378+
379+
上面例子是将iframe窗口之中的节点oldNode,克隆进入当前文档。
380+
381+
注意,克隆节点之后,还必须用appendChild方法将其加入当前文档,否则不会显示。换个角度说,这意味着插入外部文档节点之前,必须用document.importNode方法先将这个节点准备好。
382+
383+
document.importNode方法接受两个参数,第一个参数是外部文档的DOM节点,第二个参数是一个布尔值,表示是否连同子节点一起克隆,默认为false。大多数情况下,必须显式地将第二个参数设为true。
384+
344385
## Shadow DOM
345386
346387
所谓 Shadow DOM 指的是,浏览器将模板、样式表、属性、JavaScript 码等,封装成一个独立的 DOM 元素。外部的设置无法影响到其内部,而内部的设置也不会影响到外部,与浏览器处理原生网页元素(比如`<video>`元素)的方式很像。Shadow DOM 最大的好处有两个,一是可以向用户隐藏细节,直接提供组件,二是可以封装内部样式表,不会影响到外部。
@@ -799,4 +840,5 @@ template标签定义了网页元素的模板。
799840
- Eric Bidelman, [HTML Imports](http://www.html5rocks.com/en/tutorials/webcomponents/imports/)
800841
- TJ VanToll, [Why Web Components Are Ready For Production](http://developer.telerik.com/featured/web-components-ready-production/)
801842
- Chris Bateman, [A No-Nonsense Guide to Web Components, Part 1: The Specs](http://cbateman.com/blog/a-no-nonsense-guide-to-web-components-part-1-the-specs/)
843+
- [Web Components will replace your frontend framework](https://blog.usejournal.com/web-components-will-replace-your-frontend-framework-3b17a580831c), Danny Moerkerke
802844

0 commit comments

Comments
 (0)