文章詳情頁
2023年了該了解下WebComponent使用教程
瀏覽:79日期:2022-06-01 17:38:12
目錄
- 正文
- 三項主要技術
- 1、Custom elements (自定義元素)
- 生命周期函數
- 2、HTML templates(HTML 模板)
- 3、Shadow DOM(影子 DOM)
- 動態創建 webComponent 組件例子
正文
WebComponent 是官方定義的自定義組件實現方式,它可以讓開發者不依賴任何第三方框架(如Vue,React)來實現自定義頁面組件;達到組件復用效果
一個簡單例子,讓頁面顯示 hello world:
<body> <!-- 使用組件的方式 --> <my-text /> <script> class MyText extends HTMLElement { constructor() {super();this.append("hello world"); } } window.customElements.define("my-text", MyText); </script></body>
三項主要技術
1、Custom elements (自定義元素)
- 一組 JavaScript API,允許您定義 custom elements 及其行為,然后可以在您的用戶界面中按照需要使用它們
分為兩種形式:
自主定制元素:是獨立的元素,它不繼承其他內建的 HTML 元素,可以直接把它們寫成 HTML 標簽的形式,來在頁面上使用,例如我們剛才自定義的 <my-text>
自定義內置元素:繼承自內置的 HTML 元素。指定所需擴展的元素
- 使用時需通過
is
屬性指定custom element
的名稱,必須包含一個短橫線 - 注冊的時候必須使用
extends
的屬性
<!-- 自定義內置元素 使用 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
生命周期函數,處理節點操作
<!-- 自主定制元素--><body> <my-text /> <script> class MyText extends HTMLElement { constructor() {super(); } connectedCallback() {this.append("hello world"); } } window.customElements.define("my-text", MyText); </script></body>
生命周期函數
connectedCallback
:插入文檔時,可能被多次觸發,比如刪除后又添加到文檔
disconnectedCallback
:從文檔刪除時,可配置做清理工作
adoptedCallback
:被移動新文檔時
attributeChangedCallback
:屬性變化時
- 配合
observedAttributess
屬性一起使用,指定監聽的屬性 - 使用
setAttribute
方法更新屬性
不同操作觸發的生命周期函數:
例子:
<body> <div id="container"> <p is="my-text" text="云牧" id="myText"></p> </div> <button id="btnUpdateText">更新屬性</button> <button id="btnRemove">刪除節點</button> <button id="btnRestore">恢復節點</button> <button id="btnAdopt">移動節點</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 = ""; } // 監測的屬性 static get observedAttributes() {return ["text"]; } attributeChangedCallback(name, oldValue, newValue) {console.log("生命周期:attributeChangedCallback", name, oldValue, newValue);// 最先觸發是此函數,判斷是不是第一次觸發,第一次的話,只由 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 模板字串符的方式創建模板,提示不友好,復用性差
<body> <product-item name="關東煮" 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 src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" /> <div></div> <div></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 src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" /> <div></div> <div></div> </template> <product-item name="關東煮" 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);// 插入克隆的模板內容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>標題</div> <slot name="slot-des">默認內容</slot> </template> <test-item> <div slot="slot-des">不是默認內容</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,其內部樣式不共享
<body> <!-- 不受外部 .container.container 的顏色影響 --> <my-item-s></my-item-s> <div>My item</div> <style> .container.container { color: green; } </style> <template id="tpl"> <style> .container {color: pink; } </style> <div>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,其內部元素不可以直接被訪問到
有一個重要的參數 mode
- open: shadow root 元素通過 js 從外部訪問根節點
- closed:拒絕 js 從外部訪問關閉的 shadow root 節點
<body> <template id="tpl"> <div></div> <div></div> </template> <note-item title="標題" des="內容"></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 則可以繼續訪問操作內部 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>
動態創建 webComponent 組件例子
- 通過創建 商品 組件,并使得點擊能跳轉
<body> <div id="product-list"></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> <img src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" /> <div></div> <div></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: "關東煮",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 => { // 創建組件 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使用教程的詳細內容,更多關于WebComponent使用教程的資料請關注其它相關文章!
標簽:
JavaScript
排行榜