ホームページ  >  記事  >  ウェブフロントエンド  >  カスタムタグとShadow DOMでHTMLを強化する

カスタムタグとShadow DOMでHTMLを強化する

WBOY
WBOYオリジナル
2023-08-29 09:37:071072ブラウズ

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

前回の記事では、カスタム タグの作成の基本について説明しました。実際、カスタム タグを使用すると、優れた Web アプリケーションを構築する際の脆弱性の一部が解消されます。ただし、制御の追求は止まらず、従来のカスタム タグではパフォーマンスの高いアプリケーションを構築するのに十分ではありません。たとえば、カスタム タグを追加すると、コード内のスタイル セレクターの数が増える場合があります。これは、パフォーマンスの問題を引き起こす可能性のある多くの要因のうちの 1 つにすぎません。

この問題を解決する 1 つの方法は、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 は Web サイトのバックボーンです。わずか数分でページを作成できます。ブラウザでページを開くと、DOM が機能します。ブラウザがページを読み込むと、HTML のデータ モデルへの解析が開始されます。データ モデルは、ノードが HTML の要素を表すツリー構造です。データ モデルは、コードを使用して簡単に変更および操作できます。

欠点は、Web ページ全体、さらには複雑な Web アプリケーションさえも単一のデータ構造として扱われることです。これをデバッグするのは簡単ではありません。たとえば、あるコンポーネントに適用された CSS スタイルが、アプリケーション内の他のコンポーネントに影響を与える可能性があります。

インターフェースの一部を残りから分離したい場合は、iframes を使用します。ただし、iframe は重く、制限が非常に厳しいです。

これが、Shadow DOM が導入された理由です。これは、Web 開発者が DOM 内のさまざまな要素のサブツリーを含めることができる、最新のブラウザーの強力な機能です。 DOM のこれらのサブツリーは、メインのドキュメント ツリーには影響しません。技術的には、これらは シャドウ ツリー と呼ばれます。

シャドウ ツリーには シャドウ ルート があり、DOM 内の親に接続されます。この親は シャドウ ホスト と呼ばれます。

たとえば、<input type="range"> を WebKit を搭載したブラウザに接続すると、スライダーに変換されます。なぜ?これは、サブツリー DOM 要素の 1 つが「スコープ」を理解して外観を変更し、スライダーのような機能を導入するため、スライダーです。これは、Shadow DOM がタブにもたらす利点です。

うわー、それはたくさんの理論があります。ここで、Shadow DOM がどのように実装されるかを確認するためにコードを作成してみるとよいでしょう。

Shadow DOM の使用に関するステップバイステップ ガイド

ステップ 1: Shadow DOM 要素を作成する

element.attachShadow() を使用して、Shadow DOM 要素を作成します。

サンプル

tuts-tab では、Shadow DOM 要素の作成に使用されるコードが表示されます。 リーリー

ステップ 2. シャドウ ルートにコンテンツを追加する

次に、

.innerHTML を使用してコンテンツをシャドウ ルートに追加します。これが Shadow DOM を設定する唯一の方法ではないことに注意してください。 Shadow DOM の設定に役立つ API が多数あります。 リーリー

ステップ 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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。