Web Components(web组件)
web组件是一种可以复用的html单元,他是浏览器的一部分,所以不需要引入额外的库来使用他。
Web Components技术主要由以下4部分组成,但是每一部分都可以单独使用
- Custom Elments(自定义元素)
- HTML Templates(html模板)
- Shadow DOM
- HTML Imports
1
<link rel="import" href="myfile.html">
Custom Elements
自定义元素提供了一种可以让你创建自定义html元素的能力。它也是web componnets技术的组成部分,但是你也可以独立使用它们。
自定义元素有着自己的生命周期,这就意味着你可以在不同的生命周期阶段通过脚本绑定不同的行为。
例如,当它们被插入到dom中(connected),当它们从dom中移除时(disconnected),又或者它们的特性发生改变的时候(attributeChanged),你都可以在相应的时期做你想做的事情。
自定义元素的方法
constructor()
当元素被创建或者更新的时候调用
connectedCallback()
当元素被插入到文档流中或者被插入到shadow dom中的时候调用
disconnectedCallback()
当元素从文档流中移除的时候调用
attributeChangedCallback(attributeName, oldValue, newValue, namespace)
当元素被观察的特性被改变,被追加,被移除,被取代的时候调用
adoptedCallback(oldDocument, newDocument)
当元素被插入到一个新的文档流中的时候调用
自定义元素更多的时候我们采用es6类语法来进行创建:1
2
3
4
5
6<template id="custom">
<div>第一行</div>
<div>第二行</div>
</template>
<my-element name="test" id="test"></my-element>
1 | class MyElement extends HTMLElement{ |
Observed attributes
如果要使用自定义元素的attributeChangedCallback来观察自定义元素特性的变化,那么必须在初始化自定义元素的构造器中列出需要观察的特性–在类中使用静态的get存取器列出需要观察的特性。
改造上面的例子: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
32class MyElement extends HTMLElement{
constructor(){
// 一定要记得先调用父类构造器,因为我们在子类的构造器中使用了this
// 否则就报错
super()
var tplContent = document.getElementById('custom').content
var shadowRoot = this.attachShadow({ mode: 'open' })
shadowRoot.appendChild(tplContent)
}
static get observedAttributes(){ return ['name'] }
attributeChangedCallback(attr, oldValue, newValue){
console.log('oldValue: ', oldValue)
console.log('newValue: ', newValue)
if('name' === attr){
this.textContent = `Hello, ${newValue}`
}
}
connectedCallback(){
console.log('自定义元素被插入到shadow dom中')
}
}
customElements.define('my-element', MyElement)
setTimeout(function(){
document.getElementById('test').setAttribute('name', 'ggsmd')
}, 5000)
控制台输出如下:1
2
3
4
5
6
7// 初始化的时候输出
oldValue: test
newValue: null
// 5s之后输出
oldValue: test
newValue: ggsmd
HTML Templates
元素中的内容在页面加载的时候并不会渲染,但是你可以通过js来操作其中的内容。
你可以认为元素中保存了你接下来要使用的内容片段,在页面加载的时候,解析引擎并不处理中内容,也不做任何渲染,引擎只确保中的内容是否有效。
1 | <table id="producttable"> |
1 | // 检查浏览器是否支持template元素 |
HTMLTemplateElement接口
通过HTMLTemplateElement接口,我们可以操作元素中的内容
上图是HTMLTemplateElement接口的继承图,也就是说HTMLTemplateElement继承了HTMLElement上所有的属性和方法。
HTMLTemplateElement特有的一个属性
HTMLTemplateElement.content:只读的属性
返回值:返回元素中的内容,是一个DocumentFragment
1 | <template id="test"> |
1 | document.querySelector('#test').content.nodeType === 11 |
Shadow DOM
Shadow DOM为Web Components中的DOM, CSS提供了一个包装。
Shadow DOM将Web Components中的DOM, CSS和文档流中的dom进行了一个隔离。因为一个大型网页,如果前期css组织的不合理,就会导致css各种覆盖,从而使网页样式变得难以把控。通过shadow dom,可以进行一个隔离。
它是Web Components技术的一部分,但是你也可以单独使用它们。
基本的使用
shadow dom必须被绑定到某一个存在的元素上,这个元素可以是html文档流中已经存在的元素,也可以是通过js创建的元素(包括自定义元素)。
1 | <body> |
shadow dom的样式
继续接着上面的例子,如果我们需要给shadow dom添加样式。就跟我们平时使用内联样式一样,只不过将style标签极其里面的样式全部作为shadow dom的innerHTML。如下:
1 | shadow.innerHTML = '<style>span { color: red; }</style>' |
shadow dom相关API
1 | var shadowRoot = element.attachShadow(shadowRootInit) |
绑定一个shadow dom树到一个指定的元素上,并且返回ShadowRoot的引用。
shadowRoot也是一个文档片段。shadowRoot.nodeType === 11
shadowRootInit是一个如下的对象:1
2
3
4{
mode: 'open'
// mode: 'closed'
}
- open: 指定开放的包裹模式,这就意味着在外面可以使用
element.shadowRoot
来访问shadow dom中的内容。
1 | element.shadowRoot === shadowRoot(通过attachShadow返回的shadowRoot的引用) |
- closed: 指定为闭合的包裹模式,这就意味着在外面无法使用任何方法来访问shadow dom中的内容。
1 | element.shadowRoot === shadowRoot(通过attachShadow返回的shadowRoot的引用) |
ShadowRoot接口
ShadowRoot.mode
只读,返回值为’open’或者’closed’
ShadowRoot.host
只读,返回shadow dom的宿主元素
ShadowRoot.innerHTML
返回ShadowRoot内部的dom树
slot元素
slot, 翻译为“插槽”。slot元素也是web components技术的一个组成单元:他是web components内的一个占位符,通过这个占位符,你可以在接下来使用的web组件内插入自己想要的标签。
slot元素一般情况下和template元素组合使用。
Attributes(特性)
slot元素和其他的html元素一样,有着一些通用的属性,比如
style
,class
等,具体有哪些,可以参看这里
Attributes之name特性
给slot元素添加一个名字,因为一个web组件内部可能有多个slot,可以用name特性加以区分。没有添加name特性的slot元素,可以理解为
name=""
。
在Vue框架中,也有内置的slot组件,它实现的功能和标准web components中的slot元素是一样的。但在Vue中,没有添加name特性的slot组件,相当于name="default"
。
1 | <template id="slot-template"> |
1 | var slots = document.querySelector('#slot-template') |