Web Component是HTML5推出的一个新特征,就是web组件,它描述的其实是三种不同的的API:自定义元素,Shadow DOM和HTML模板.
自定义元素
: 在 HTML 基础标签外扩展自定义标签元素
Shadow DOM
: 主要用于将 Shadow DOM 的内容与外层document DOM 隔离
HTML 模板
: 使用 <template> 来定义组件模板,使用 <slot> 作为插槽使用
class DiyButton extends HTMLElement {
constructor() {
super();
let value = this.getAttribute("value");
// 可以直接放入到innerHTML中
// this.innerHTML = `<button>custom-button ${value}</button>`
// 也可以通过appendChild的方式添加元素对象
let btn = document.createElement("button");
btn.innerHTML = `custom-button ${value}`;
btn.addEventListener('click', () => {
this.setAttribute("name", "testtest");
this.setAttribute("value", 9999);
})
this.appendChild(btn);
}
// 当 custom element首次被插入文档DOM时,被调用
connectedCallback() {
console.log("connectedCallback");
}
// 当 custom element从文档DOM中删除时,被调用
disconnectedCallback() {
console.log("disconnectedCallback");
}
// 当 custom element增加、删除、修改自身属性时,被调用
attributeChangedCallback(name, oldValue, newValue) {
console.log("attribute", name, oldValue, newValue);
}
// 声明需要监听的属性名,只有这些属性变化时才会触发attributeChangedCallback
static get observedAttributes() {
return ["name", "url", "value"];
}
}
//参数一:自定义元素名,格式有要求:短线连接的字符串
//参数二:自定义元素构造器
//参数三:可选,含有 extends 属性的对象。指定所创建的元素继承自哪个内置元素,可以继承任何内置元素
window.customElements.define("Diy-button", DiyButton );
<!DOCTYPE html>
<html lang="en">
<body>
<button>点击</button>
<diy-button
name="app-button"
url="www.baidu.com"
value="90"
></diy-button>
</body>
<script src="diy.js"></script>
<script>
const customButton = document.querySelector("diy-button");
//要注意,写在这里是整个自定义元素的事件,也就是说,自定义元素里面的每一个元素,都会触发click事件
customButton.addEventListener("click", function (e) {
this.setAttribute("name", "test");
this.setAttribute("value", 99);
});
</script>
</html>
Shadow DOM 是 Web components 的一个重要属性是封装——可以将标记结构、样式和行为隐藏起来, 并与页面上的其他代码相隔离
,保证不同的部分不会混在一起,可使代码更加干净、整洁。其中,Shadow DOM 接口是关键所在,它可以将一个隐藏的、独立的 DOM 附加到一个元素上。
class DiyButton extends HTMLElement {
constructor() {
super();
let btn = document.createElement("button");
btn.innerHTML = `Diy-button ${value}`;
//其他代码省略只保留关键代码...
//创建Shadow DOM时,可以选择open或closed模式,
//close会对外部DOM隐藏shadowRoot,这可以防止其他脚本对DOM的以外操作
//除非有特殊需求,建议默认open
this.attachShadow({ mode: "open" });
//这里的样式,只会作用域当前的shadowRoot中,不会影响到外部的DOM
this.shadowRoot.innerHTML = `
<style>
button {
color: red;
}
</style>
`;
this.shadowRoot.appendChild(btn);
}
//其他代码省略只保留关键代码
}
<template id="add-template">
<input type="text">
<button>新增</button>
</template>
class DiyButton extends HTMLElement {
constructor() {
super();
let value = this.getAttribute("value");
let templateEle = document.getElementById("add-template");
let cloneEle = templateEle.content.cloneNode(true);
cloneEle.querySelector("input[type='text']").value = `${value}`;
let btn = document.createElement("button");
btn.innerHTML = `custom-button ${value}`;
btn.addEventListener('click', () => {
this.setAttribute("name", "test");
this.setAttribute("value", 89);
})
this.attachShadow({ mode: "open" });
this.shadowRoot.innerHTML = `
<style>
button {
color: red;
}
</style>
`;
this.shadowRoot.appendChild(btn);
this.shadowRoot.appendChild(cloneEle);
}
}
还能使用slot插槽
<template id="add-template">
<slot name="title"></slot>
<input type="text">
<button>新增</button>
</template>
<Diy-button
name="app-button"
url="www.baidu.com"
value="90"
>
<div slot="title">
<h2>新增</h2>
</div>
</Diy-button>