<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
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>
分為兩種形式:
自主客製化元素:是獨立的元素,它不繼承其他內建的 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>
<body> <product-item name="關東煮" img="//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="關東煮" img="//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 class="title">標題</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>
影子DOM,其內部樣式不共用
<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,其內部元素不可以直接被存取到
有一個重要的引數 mode
<body> <template id="tpl"> <div class="title"></div> <div class="des"></div> </template> <note-item class="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>
<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: "關東煮", img: "//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp", id: "10026249568453", price: 49.8 }, { name: "土雞蛋", img: "//img11.360buyimg.com/seckillcms/s200x200_jfs/t1/172777/32/27438/130981/61fbd2e0E236000e0/7f5284367e2f5da6.jpg!cc_200x200.webp", id: "10024773802639", price: 49.8 }, { name: "東北蜜棗粽子", img: "//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使用教學的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45