2023年了該了解下WebComponent使用教程
正文
WebComponent 是官方定義的自定義組件實現(xiàn)方式,它可以讓開發(fā)者不依賴任何第三方框架(如Vue,React)來實現(xiàn)自定義頁面組件;達到組件復(fù)用效果
一個簡單例子,讓頁面顯示 hello world:
<body>
<!-- 使用組件的方式 -->
<my-text />
<script>
class MyText extends HTMLElement {
constructor() {
super();
this.append("hello world");
}
}
window.customElements.define("my-text", MyText);
</script>
</body>
三項主要技術(shù)
1、Custom elements (自定義元素)
- 一組 JavaScript API,允許您定義 custom elements 及其行為,然后可以在您的用戶界面中按照需要使用它們
分為兩種形式:
自主定制元素:是獨立的元素,它不繼承其他內(nèi)建的 HTML 元素,可以直接把它們寫成 HTML 標簽的形式,來在頁面上使用,例如我們剛才自定義的 <my-text>
自定義內(nèi)置元素:繼承自內(nèi)置的 HTML 元素。指定所需擴展的元素
- 使用時需通過
is屬性指定custom element的名稱,必須包含一個短橫線 - 注冊的時候必須使用
extends的屬性
<!-- 自定義內(nèi)置元素 使用 is-->
<body>
<!-- 使用組件的方式 -->
<p is="color-p" color="green">云牧</p>
<script>
class ColorP extends HTMLParagraphElement {
constructor() {
super();
this.style.color = this.getAttribute("color");
}
}
window.customElements.define("color-p", ColorP, { extends: "p" });
</script>
</body>
推薦在 connectedCallback 生命周期函數(shù),處理節(jié)點操作
<!-- 自主定制元素-->
<body>
<my-text />
<script>
class MyText extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.append("hello world");
}
}
window.customElements.define("my-text", MyText);
</script>
</body>
生命周期函數(shù)
connectedCallback:插入文檔時,可能被多次觸發(fā),比如刪除后又添加到文檔
disconnectedCallback:從文檔刪除時,可配置做清理工作
adoptedCallback:被移動新文檔時
attributeChangedCallback:屬性變化時
- 配合
observedAttributess屬性一起使用,指定監(jiān)聽的屬性 - 使用
setAttribute方法更新屬性
不同操作觸發(fā)的生命周期函數(shù):

例子:
<body>
<div id="container">
<p is="my-text" text="云牧" id="myText"></p>
</div>
<button id="btnUpdateText">更新屬性</button>
<button id="btnRemove">刪除節(jié)點</button>
<button id="btnRestore">恢復(fù)節(jié)點</button>
<button id="btnAdopt">移動節(jié)點</button>
<iframe src="./ifr.html" id="ifr"></iframe>
<script>
class MyText extends HTMLParagraphElement {
constructor() {
super();
}
connectedCallback() {
console.log("生命周期:connectedCallback");
this.append("你好:" + this.getAttribute("text"));
}
disconnectedCallback() {
console.log("生命周期:disconnectedCallback");
this.innerHTML = "";
}
// 監(jiān)測的屬性
static get observedAttributes() {
return ["text"];
}
attributeChangedCallback(name, oldValue, newValue) {
console.log("生命周期:attributeChangedCallback", name, oldValue, newValue);
// 最先觸發(fā)是此函數(shù),判斷是不是第一次觸發(fā),第一次的話,只由 connectedCallback 處理
if (oldValue != null) {
this.replaceChildren("你好:" + newValue);
}
}
adoptedCallback() {
console.log("生命周期:adoptedCallback");
}
}
window.customElements.define("my-text", MyText, { extends: "p" });
const myText = document.getElementById("myText");
btnUpdateText.addEventListener("click", function (e) {
myText.setAttribute("text", "黛玉");
});
btnRemove.addEventListener("click", function (e) {
myText.remove();
});
btnRestore.addEventListener("click", function (e) {
container.appendChild(myText);
});
btnAdopt.addEventListener("click", () => {
const textNode = ifr.contentWindow.document.getElementById("myText");
container.appendChild(document.adoptNode(textNode));
});
</script>
</body>
2、HTML templates(HTML 模板)
- 使用 JS 模板字串符的方式創(chuàng)建模板,提示不友好,復(fù)用性差
<body>
<product-item
name="關(guān)東煮"
img="http://img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
price="49.8"
></product-item>
<script>
class ProductItem extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const content = `
<img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
<div class="name"></div>
<div class="price"></div>
`;
this.innerHTML = content;
this.querySelector(".img").src = this.getAttribute("img");
this.querySelector(".name").innerText = this.getAttribute("name");
this.querySelector(".price").innerText = this.getAttribute("price");
}
}
window.customElements.define("product-item", ProductItem);
</script>
</body>
template 方式
<body>
<!-- template -->
<template id="tpl-product-item">
<img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
<div class="name"></div>
<div class="price"></div>
</template>
<product-item
name="關(guān)東煮"
img="http://img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
price="49.8"
></product-item>
<script>
class ProductItem extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const content = document.getElementById("tpl-product-item").content.cloneNode(true);
// 插入克隆的模板內(nèi)容
this.append(content);
this.querySelector(".img").src = this.getAttribute("img");
this.querySelector(".name").innerText = this.getAttribute("name");
this.querySelector(".price").innerText = this.getAttribute("price");
}
}
window.customElements.define("product-item", ProductItem);
</script>
</body>
slot
<body>
<template id="tpl-test">
<style>
.title {
color: green;
}
</style>
<div class="title">標題</div>
<slot name="slot-des">默認內(nèi)容</slot>
</template>
<test-item>
<div slot="slot-des">不是默認內(nèi)容</div>
</test-item>
<script>
class TestItem extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const content = document.getElementById("tpl-test").content.cloneNode(true);
const shadow = this.attachShadow({ mode: "open" });
shadow.append(content);
}
}
window.customElements.define("test-item", TestItem);
</script>
</body>
3、Shadow DOM(影子 DOM)

影子DOM,其內(nèi)部樣式不共享
<body>
<!-- 不受外部 .container.container 的顏色影響 -->
<my-item-s></my-item-s>
<div class="container">My item</div>
<style>
.container.container {
color: green;
}
</style>
<template id="tpl">
<style>
.container {
color: pink;
}
</style>
<div class="container">My Item</div>
</template>
<script>
class MyItemShadow extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const content = document.getElementById("tpl").content.cloneNode(true);
const shadow = this.attachShadow({ mode: "open" });
shadow.append(content);
}
}
window.customElements.define("my-item-s", MyItemShadow);
</script>
</body>
影子DOM,其內(nèi)部元素不可以直接被訪問到
有一個重要的參數(shù) mode
- open: shadow root 元素通過 js 從外部訪問根節(jié)點
- closed:拒絕 js 從外部訪問關(guān)閉的 shadow root 節(jié)點
<body>
<template id="tpl">
<div class="title"></div>
<div class="des"></div>
</template>
<note-item class="note-item" title="標題" des="內(nèi)容"></note-item>
<script>
class NoteItem extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const content = document.getElementById("tpl").content.cloneNode(true);
const shadow = this.attachShadow({ mode: "open" });
shadow.append(content);
// 如果是 open 則可以繼續(xù)訪問操作內(nèi)部 dom
// console.log(document.querySelector(".note-item").shadowRoot.querySelector(".title"));
shadow.querySelector(".title").textContent = this.getAttribute("title");
shadow.querySelector(".des").textContent = this.getAttribute("des");
}
}
window.customElements.define("note-item", NoteItem);
</script>
</body>
引入外部樣式:
<body>
<template id="tpl">
<!-- 方式一: -->
<link rel="stylesheet" href="index.css" rel="external nofollow" />
<div>My Item</div>
</template>
<my-item></my-item>
<script>
class MyItem extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const content = document.getElementById("tpl").content.cloneNode(true);
const shadow = this.attachShadow({ mode: "open" });
shadow.append(content);
// 方式二:
const linkEl = document.createElement("link");
linkEl.setAttribute("rel", "stylesheet");
linkEl.setAttribute("href", "index.css");
shadow.appendChild(linkEl);
}
}
window.customElements.define("my-item", MyItem);
</script>
</body>
動態(tài)創(chuàng)建 webComponent 組件例子
- 通過創(chuàng)建 商品 組件,并使得點擊能跳轉(zhuǎn)
<body>
<div id="product-list" style="display: flex"></div>
<template id="product-item">
<style>
.product-item {
margin-left: 15px;
cursor: pointer;
}
.img {
width: 100px;
}
.name {
text-align: center;
}
.price {
color: #999;
text-align: center;
}
</style>
<div class="product-item">
<img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
<div class="name"></div>
<div class="price"></div>
</div>
</template>
<script>
class ProductItemElement extends HTMLElement {
constructor(props) {
super(props);
this.addEventListener("click", () => {
window.open(`https://item.jd.com/${this.id}.html`);
});
}
connectedCallback() {
const shadow = this.attachShadow({ mode: "open" });
const content = document.getElementById("product-item").content.cloneNode(true);
content.querySelector(".img").src = this.img;
content.querySelector(".name").innerText = this.name;
content.querySelector(".price").innerText = this.price;
shadow.appendChild(content);
}
}
window.customElements.define("product-item", ProductItemElement);
</script>
<script>
const products = [
{
name: "關(guān)東煮",
img: "http://img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp",
id: "10026249568453",
price: 49.8
},
{
name: "土雞蛋",
img: "http://img11.360buyimg.com/seckillcms/s200x200_jfs/t1/172777/32/27438/130981/61fbd2e0E236000e0/7f5284367e2f5da6.jpg!cc_200x200.webp",
id: "10024773802639",
price: 49.8
},
{
name: "東北蜜棗粽子",
img: "http://img20.360buyimg.com/seckillcms/s200x200_jfs/t1/129546/31/19459/110768/60b1f4b4Efd47366c/3a5b80c5193bc6ce.jpg!cc_200x200.webp",
id: "10035808728318",
price: 15
}
];
const productList = document.getElementById("product-list");
const elList = products.map(product => {
// 創(chuàng)建組件
const el = document.createElement("product-item");
el.img = product.img;
el.name = product.name;
el.price = product.price;
el.id = product.id;
return el;
});
productList.append.apply(productList, elList);
</script>
</body>以上就是2023年了該了解下WebComponent使用教程的詳細內(nèi)容,更多關(guān)于WebComponent使用教程的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS前端二維數(shù)組生成樹形結(jié)構(gòu)示例詳解
這篇文章主要為大家介紹了JS前端二維數(shù)組生成樹形結(jié)構(gòu)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
axios?攔截器管理類鏈式調(diào)用手寫實現(xiàn)及原理剖析
這篇文章主要為大家介紹了axios?攔截器管理類鏈式調(diào)用手寫實現(xiàn)及原理剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
Electron?網(wǎng)絡(luò)攔截實戰(zhàn)示例詳解
這篇文章主要為大家介紹了Electron?網(wǎng)絡(luò)攔截實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
js c++ vue方法與數(shù)據(jù)交互通信示例
這篇文章主要為大家介紹了js c++ vue方法與數(shù)據(jù)交互通信示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08
微信小程序 頁面跳轉(zhuǎn)和數(shù)據(jù)傳遞實例詳解
這篇文章主要介紹了微信小程序 頁面跳轉(zhuǎn)和數(shù)據(jù)傳遞實例詳解的相關(guān)資料,這里附有實例代碼幫助到家學習理解,需要的朋友可以參考下2017-01-01

