WebComponents是一套不同的技术,可以创建可重用的定制元素,可以在web应用中使用它们。
一个重要属性就是封装,可以将标记结构,样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不会混在一起,可使代码更加干净,整洁
web-componetns 有三项主要技术组成,可以用来一起使用来创建、封装定制的元素。
- Custom elements - 自定义元素,允许自定义custom elements及其行为,然后可以在用户界面中按照需求来使用
- Shadow Dom - 用于将封装的影子dom树附加到元素并控制其关联的功能。可以保持元素的功能私有,这样它们就可以被校本化和样式化,而不用担心与文档的其他部分发生冲突
HTML templates - 有template和slot元素可以编写不在呈现页面中显示的标记模版。可被多次重用
Web Component
<web-card></web-card>
<script>
customElements.define("web-card", class extends HTMLElement {
constructor() {
super()
let title = document.createElement("h1");
title.textContent = "Web Components";
this.append(title);
}
})
</script>
获取属性
<web-card data-content="web-card" list="[1,2,3,4]"></web-card> this.dataset.content // web-card this.getAttribute("list") //[1,2,3,4]
添加事件处理器
customElements.define("web-card", class extends HTMLElement { constructor() { super() console.dir(this); console.log(this.getAttribute("list")); let title = document.createElement("h1"); title.textContent = "Web Components"; this.addEventListener("click",this.onClick); this.append(title); } onClick = () => { console.log("clicked"); } })
生命周期函数
connectedCallback: 当自定义元素第一次被连接到文档DOM时被调用。
- disconnectedCallback: 当自定义元素与文档DOM断开连接时被调用。
- adoptedCallback: 当自定义元素被移动到新文档时被调用。
attributeChangedCallback: 当自定义元素的一个属性被增加、移除或更改时被调用。 ```javascript class Card extends HTMLElement { constructor() { super() } connectedCallback() { console.log(“connectedCallback”); } disconnectedCallback() { console.log(“disconnectedCallback”); } adoptedCallback() { console.log(“adoptedCallback”); }
// 一个镜头属性,返回组件需要检测的属性,属性值在变化的时候毁掉函数才会被执行 static get observedAttributes() {return [ ; }
attributeChangedCallback() { console.log(“attributeChangedCallback”); }
}
<a name="sExSQ"></a>
### CustomElementRegistry
1. define - 定义一个新元素,第三个参数为一个选项
1. upgrade - 将更新节点子树中所有包含阴影的自定义元素。将一个自定义标签升级成可使用的标签
1. whenDefined - 查询一个自定义标签,当元素被定义时返回一个promise
1. get - 返回指定自定义元素的构造函数,如果未定义返回undefined
```javascript
setTimeout(() => {
customElements.define("web-card", class extends HTMLElement {
constructor() {
super()
let title = document.createElement("h1");
title.textContent = "Web Components";
this.append(title);
}
},{});
},3000);
// 在三秒以后,webCard被定义,promise返回
customElements.whenDefined("web-card").then(() => {
console.log('元素被定义');
});
Shadow Dom
像是影子一样,在文档中默认不会展示原有的html内容,会展示dom结构树中已经定义的内容
<proto-card></proto-card>
<script>
class Proto extends HTMLElement {
constructor() {
super()
const dom = this.attachShadow({ mode: "open" })
const p = document.createElement("p")
p.textContent = "shadow dom"
p.addEventListener("click",() => console.log("p clicked"))
dom.append(p)
}
}
customElements.define("proto-card", Proto)
</script
HTML Template
模版元素使一种保存客户端内容机制,该内容在加载页面时不会呈现。可以在运行时进行实例化
将模版视为一个可存储在文档中以便后续使用的内容片段。
模版中定义的内容存储在content
属性中。 该属性是只读的
<template id="temp">
<style>
.box {
border: 1px solid red;
}
.box > h3 {
color: royalblue;
}
.box > p {
color: slategray;
font-size: 18px;
}
</style>
<div class="box">
<h3>title</h3>
<p>content</p>
</div>
</template>
<script>
// 要cloneNode(true) 表示深克隆,不然模版只能使用一次
dom.append(temp.content.cloneNode(true)); // 在shadow dom 中使用
this.append(temp.content.cloneNode(true)); // 在自定义元素中使用
</script>
效果
样式的隔离
<style type="text/css">
.box {
background: red;
}
</style>
<div class="box">
bod top
</div>
<template id="app">
<style>
.box {
background: blue;
}
</style>
</template>
<script type="text/javascript">
class Proto extends HTMLElement {
constructor() {
super()
const dom = this.attachShadow({ mode: "open" });
const p = document.createElement("p");
p.textContent = "shadow dom";
p.classList.add("box");
dom.append(document.querySelector("#app").content.cloneNode(true));
dom.append(p);
window.foo = "true";
}
}
customElements.define("proto-card", Proto);
</script>
<proto-card ></proto-card>
<script type="text/javascript">
console.log(foo)
</script>