首頁  >  文章  >  web前端  >  使用自訂標籤和 Shadow DOM 增強 HTML

使用自訂標籤和 Shadow DOM 增強 HTML

WBOY
WBOY原創
2023-08-29 09:37:071071瀏覽

使用自定义标签和 Shadow DOM 增强 HTML

在上一篇文章中,我解釋了建立自訂標籤的基礎知識。事實上,自訂標籤消除了建立優秀 Web 應用程式時的一些脆弱性。然而,對控制的追求並沒有停止,傳統的自訂標籤不足以建立效能豐富的應用程式。例如,程式碼中樣式選擇器的數量可能會隨著自訂標籤的增加而增加。這只是可能導致效能問題的眾多因素之一。

解決此問題的一種方法是透過 Shadow DOM。

Shadow DOM 透過引入作用域樣式來運作。它不需要任何特殊的命名約定或工具。使用 Shadow DOM,將 CSS 與標記捆綁起來變得很簡單。此外,此功能可讓我們隱藏有關普通 JavaScript 中實作的所有細節。

為什麼要使用 Shadow DOM?

Shadow DOM 提供以下解決方案:

  • 允許 DOM 中的獨立元素。諸如 document.querySelector 之類的查詢不會傳回孤立的元素。
  • 允許作用域 CSS。作用域 CSS 確保所有樣式規則都保留在頁面內。它也意味著更簡單的 CSS 選擇器,沒有任何命名衝突和許多通用類別。

我們的範例

為了示範 Shadow DOM,我們將使用一個名為 tuts-tabs 的簡單元件。本文中的所有引用都將指向這段程式碼。要體驗 Shadow DOM,請看下面的示範:

了解 Shadow DOM

什麼是 Shadow DOM?

在開始使用 Shadow DOM 進行編碼之前,您需要了解常規 DOM。

HTML 是網站的支柱。只需幾分鐘,您就可以建立一個頁面。當您在瀏覽器中開啟該頁面時,DOM 開始發揮作用。一旦瀏覽器載入頁面,它就會開始將 HTML 解析為資料模型。此資料模型是一個樹狀結構,其中的節點代表 HTML 中的元素。這個資料模型很容易用程式碼修改和操作。

缺點是整個網頁甚至複雜的 Web 應用程式都會被視為單一資料結構。這不太容易調試!例如,適用於一個元件的 CSS 樣式最終可能會影響應用程式中其他位置的另一個元件。

當您想要將介面的一部分與其餘部分隔離時,可以使用 iframes。但 iframe 很重且限制性極大。

這就是引入 Shadow DOM 的原因。它是現代瀏覽器的一項強大功能,可讓 Web 開發人員在 DOM 中包含各種元素的子樹。 DOM 的這些子樹不會影響主文檔樹。從技術上講,它們被稱為影子樹

影子樹有一個影子根,它附加到 DOM 中的父級。此父級稱為影子主機

例如,如果您將 <input type="range"> 插入由 WebKit 提供支援的瀏覽器,它將轉換為滑桿。為什麼?這是一個滑桿,因為子樹 DOM 元素之一了解「範圍」以更改其外觀並引入類似滑桿的功能。這是 Shadow DOM 為選項卡帶來的優勢。

哇,這是很多理論。現在,您可能想要編寫一些程式碼來了解如何實作 Shadow DOM。

使用 Shadow DOM 的逐步指南

第 1 步:建立 Shadow DOM 元素

使用 element.attachShadow() 建立 Shadow DOM 元素。

在我們的範例 tuts-tab 中,您將看到用於建立 Shadow DOM 元素的程式碼。

 let shadowRoot = this.attachShadow({mode: 'open'});

第 2 步. 將內容加入到 Shadow Root

接下來,我們將使用 .innerHTML 將內容新增到影子根目錄。請注意,這不是填充 Shadow DOM 的唯一方法。有許多 API 可以幫助您填充 Shadow DOM。

shadowRoot.innerHTML = ``

第 3 步:將自訂元素連接到 Shadow DOM

將自訂元素連接到 Shadow DOM 非常簡單。請記住,當您將自訂元素與 Shadow DOM 組合時,您將能夠使用 CSS、JavaScript 和 HTML 建立封裝元件。因此,您將建立一個可以在您的應用程式中重複使用的全新 Web 元件。

在我們的範例中,我們使用 customElements.define() 建立一個新的自訂元素。如上一教學所提到的,新元素的名稱應包含「-」。 tuts-tabs 元件擴充了 HTMLElement

当我们扩展 HTMLElement 时,在构造函数中调用 super() 非常重要。另外,构造函数是需要创建 shadowRoot 的地方。

customElements.define('tuts-tabs', class extends HTMLElement {
    constructor() {
    super(); // always call super() first in the constructor.

    // Attach a shadow root to <tuts-tabs>.
    const shadowRoot = this.attachShadow({mode: 'open'});
    ...
});

创建 shadowRoot 后,您可以为其创建 CSS 规则。 CSS 规则可以包含在 <style></style> 标记中,并且这些样式的范围仅限于 tuts-tab

customElements.define('tuts-tabs', class extends HTMLElement {
    constructor() {
    super(); 
    const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = `
         <!-- styles are scoped to tuts-tabs! -->
         <style>#tabs { ... }</style>
    `;
    }
    ...
});

第 4 步:向 Shadow DOM 添加样式

tuts-tab相关的CSS可以写在<style></style>标签内。请记住,此处声明的所有样式都将作用于 tuts-tab Web 组件。 作用域 CSS 是 Shadow DOM 的一项有用功能,它具有以下属性:

  • CSS 选择器不会影响 Shadow DOM 之外的组件。
  • Shadow DOM 中的元素不受其外部选择器的影响。
  • 样式的范围仅限于宿主元素。

如果你想在 Shadow DOM 中选择自定义元素,你可以使用 :host 伪类。当 :host 伪类用于普通 DOM 结构时,它不会产生任何影响。但在 Shadow DOM 内部,它会产生很大的差异。您将在 tuts-tab 组件中找到以下 :host 样式。它决定显示和字体样式。这只是一个简单的示例,展示如何将 :host 合并到 Shadow DOM 中。

:host 的一个问题是它的特殊性。如果父页面有 :host,它将具有更高的特异性。父样式内的所有样式都会获胜。这是从外部覆盖自定义元素内部样式的一种方法。

 :host {
  display: inline-block;
  width: 650px;
  font-family: 'Roboto Slab';
  contain: content;
}

随着 CSS 变得更简单,Shadow DOM 的整体效率也会提高。

下面定义的所有样式都是影子根的本地样式。

shadowRoot.innerHTML = `
<style>
:host {
  display: inline-block;
  width: 650px;
  font-family: 'Roboto Slab';
  contain: content;
}
#panels {
  box-shadow: 0 2px 2px rgba(0, 0, 0, .3);
  background: white;
  border-radius: 3px;
  padding: 16px;
  height: 250px;
  overflow: auto;
}
#tabs slot {
  display: inline-flex; /* Safari bug. Treats <slot> as a parent */
}
...
</style>

同样,您可以自由地在 Shadow DOM 中引入样式表。当您在 Shadow DOM 内链接样式表时,它们的作用域将位于 Shadow 树内。这是一个简单的例子来帮助您理解这个概念。

shadowRoot.innerHTML = `
<style>
:host {
  display: inline-block;
  width: 650px;
  font-family: 'Roboto Slab';
  contain: content;
}
#panels {
  box-shadow: 0 2px 2px rgba(0, 0, 0, .3);
  background: white;
  border-radius: 3px;
  padding: 16px;
  height: 250px;
  overflow: auto;
}
...
</style>
<link rel="stylesheet" href="styles.css">
...

步骤 5. 在自定义组件中定义 HTML 元素

接下来,我们可以定义 tuts-tab 的 HTML 元素。

在简单的选项卡结构中,应该有可单击的标题和反映所选标题内容的面板。这显然意味着我们的自定义元素应该有一个带有标题的 div 和一个用于面板的 div 。 HTML 组件将定义如下:

customElements.define('tuts-tabs', class extends HTMLElement {
    constructor() {
    super(); const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = `
        <style>#tabs { ... }</style>
        
        ....
        
        // Our HTML elements for tuts-tab
        <div id="tabs">...</div>
        <div id="panels">...</div>
        ...
    `;
    }
    ...
});

在面板的 div 中,您会遇到一个有趣的标签,名为 <slot></slot>。我们的下一步是了解有关插槽的更多信息。

第 6 步:在 Shadow DOM 中使用槽

Slot 在 Shadow DOM API 中起着至关重要的作用。插槽充当自定义组件内的占位符。这些组件可以由您自己的标记填充。槽声明分为三种不同类型:

  1. 您可以拥有零个插槽的组件。
  2. 您可以创建一个包含后备内容或空内容的槽位。
  3. 您可以使用整个 DOM 树创建槽。

在我们的 tuts-tabs 中,我们有一个用于选项卡标题的命名槽,以及另一个用于面板的槽。命名槽会创建您可以通过名称引用的孔。

customElements.define('tuts-tabs', class extends HTMLElement {
    constructor() {
    super(); const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = `
        <style>#tabs { ... }</style>
        
        ....
        
        // Our HTML elements for tuts-tab
        <div id="tabs">
            <slot id="tabsSlot" name="title"></slot>
         </div>
        <div id="panels">
            <slot id="panelsSlot"></slot>
        </div>
        ...
    `;
    }
    ...
});

第 7 步:填充插槽

现在,是时候填充插槽了。在之前的教程中,我们了解了定义自定义元素的四种不同方法,并且 tuts-tabs 使用其中两种方法来构建选项卡:connectedCallbackdisconnectedCallback

connectedCallback 中,我们将填充步骤 6 中定义的槽。我们的 connectedCallback 将定义如下。我们使用 querySelector 来识别 tabsSlotpanelsSlot。当然,这并不是识别 HTML 中插槽的唯一方法。

识别槽后,您需要为其分配节点。在 tuts-tab 中,我们使用以下 tabsSlot.assignedNodes 来标识选项卡的数量。

connectedCallback() {
    ...
    const tabsSlot = this.shadowRoot.querySelector('#tabsSlot');
    const panelsSlot = this.shadowRoot.querySelector('#panelsSlot');

    this.tabs = tabsSlot.assignedNodes({flatten: true});
    this.panels = panelsSlot.assignedNodes({flatten: true}).filter(el => {
      return el.nodeType === Node.ELEMENT_NODE;
    });
    ...
  }

此外,connectedCallback 是我们注册所有事件监听器的地方。每当用户单击选项卡标题时,面板的内容都需要更改。可以在 connectedCallback 函数中注册用于实现此目的的事件侦听器。

第 8 步:实现逻辑和交互性

我们不会深入探讨如何实现选项卡及其功能的逻辑。但是,请记住,我们的自定义 tuts-tab 组件中实现了以下方法,用于在选项卡之间切换:

  1. onTitleClick 该方法捕获选项卡标题上的点击事件。它有助于在选项卡面板内切换内容。
  2. selectTab该函数负责隐藏面板和显示右侧面板。此外,它还负责突出显示所选的选项卡。
  3. findFirstSelected此方法用于在第一次加载时选择选项卡。
  4. selected这是一个用于获取所选选项卡的 getter 和 setter。

第 9 步.定义生命周期方法

继续,不要忘记定义 disconnectedCallback。这是自定义元素中的生命周期方法。当自定义元素从视图中销毁时,会触发此回调。这是在应用程序中删除操作侦听器和重置控件的最佳位置之一。但是,回调的范围仅限于自定义元素。在我们的例子中,它将是 tuts-tab

第 10 步。使用新组件!

最后一步是在 HTML 中使用 tuts-tab 。我们可以很容易地在 HTML 标记中插入 tuts-tab 。这是一个简单的例子来演示其用法。

<tuts-tabs background>
  <button slot="title">Tab 1</button>
  <button slot="title" selected>Tab 2</button>
  <button slot="title">Tab 3</button>
  <section>content panel 1</section>
  <section>content panel 2</section>
  <section>content panel 3</section>
</tuts-tabs>

结论

我们开始了!我们已经完成了一个重要教程,在该教程中我们创建并使用了自定义元素。该过程很简单,并且在开发网页时被证明非常有用。我希望您尝试创建自定义元素并与我们分享您的经验。

以上是使用自訂標籤和 Shadow DOM 增強 HTML的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn