ホームページ > 記事 > ウェブフロントエンド > カスタムタグとShadow DOMでHTMLを強化する
前回の記事では、カスタム タグの作成の基本について説明しました。実際、カスタム タグを使用すると、優れた Web アプリケーションを構築する際の脆弱性の一部が解消されます。ただし、制御の追求は止まらず、従来のカスタム タグではパフォーマンスの高いアプリケーションを構築するのに十分ではありません。たとえば、カスタム タグを追加すると、コード内のスタイル セレクターの数が増える場合があります。これは、パフォーマンスの問題を引き起こす可能性のある多くの要因のうちの 1 つにすぎません。
この問題を解決する 1 つの方法は、Shadow DOM を使用することです。
Shadow DOM は、スコープ付きスタイルを導入することで機能します。特別な命名規則やツールは必要ありません。 Shadow DOM を使用すると、CSS とマークアップを簡単にバンドルできます。さらに、この機能により、プレーンな JavaScript の実装に関する詳細をすべて隠すことができます。
Shadow DOM は次のソリューションを提供します:
document.querySelector
などのクエリは、孤立した要素を返しません。 Shadow DOM をデモするために、tuts-tabs
という単純なコンポーネントを使用します。この記事内のすべての参照は、このコードを指します。 Shadow DOM を体験するには、以下のデモをご覧ください:
Shadow DOM を使用したコーディングを開始する前に、通常の DOM を理解する必要があります。
HTML は Web サイトのバックボーンです。わずか数分でページを作成できます。ブラウザでページを開くと、DOM が機能します。ブラウザがページを読み込むと、HTML のデータ モデルへの解析が開始されます。データ モデルは、ノードが HTML の要素を表すツリー構造です。データ モデルは、コードを使用して簡単に変更および操作できます。
欠点は、Web ページ全体、さらには複雑な Web アプリケーションさえも単一のデータ構造として扱われることです。これをデバッグするのは簡単ではありません。たとえば、あるコンポーネントに適用された CSS スタイルが、アプリケーション内の他のコンポーネントに影響を与える可能性があります。
インターフェースの一部を残りから分離したい場合は、iframe
s を使用します。ただし、iframe は重く、制限が非常に厳しいです。
これが、Shadow DOM が導入された理由です。これは、Web 開発者が DOM 内のさまざまな要素のサブツリーを含めることができる、最新のブラウザーの強力な機能です。 DOM のこれらのサブツリーは、メインのドキュメント ツリーには影響しません。技術的には、これらは シャドウ ツリー と呼ばれます。
シャドウ ツリーには シャドウ ルート があり、DOM 内の親に接続されます。この親は シャドウ ホスト と呼ばれます。
たとえば、<input type="range">
を WebKit を搭載したブラウザに接続すると、スライダーに変換されます。なぜ?これは、サブツリー DOM 要素の 1 つが「スコープ」を理解して外観を変更し、スライダーのような機能を導入するため、スライダーです。これは、Shadow DOM がタブにもたらす利点です。
うわー、それはたくさんの理論があります。ここで、Shadow DOM がどのように実装されるかを確認するためにコードを作成してみるとよいでしょう。
element.attachShadow() を使用して、Shadow DOM 要素を作成します。
tuts-tab では、Shadow DOM 要素の作成に使用されるコードが表示されます。
リーリー
.innerHTML を使用してコンテンツをシャドウ ルートに追加します。これが Shadow DOM を設定する唯一の方法ではないことに注意してください。 Shadow DOM の設定に役立つ API が多数あります。
リーリー
この例では、
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> `; } ... });
与tuts-tab
相关的CSS可以写在<style></style>
标签内。请记住,此处声明的所有样式都将作用于 tuts-tab
Web 组件。 作用域 CSS 是 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"> ...
接下来,我们可以定义 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>
。我们的下一步是了解有关插槽的更多信息。
Slot 在 Shadow DOM API 中起着至关重要的作用。插槽充当自定义组件内的占位符。这些组件可以由您自己的标记填充。槽声明分为三种不同类型:
在我们的 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> ... `; } ... });
现在,是时候填充插槽了。在之前的教程中,我们了解了定义自定义元素的四种不同方法,并且 tuts-tabs
使用其中两种方法来构建选项卡:connectedCallback
和 disconnectedCallback
。
在 connectedCallback
中,我们将填充步骤 6 中定义的槽。我们的 connectedCallback
将定义如下。我们使用 querySelector
来识别 tabsSlot
和 panelsSlot
。当然,这并不是识别 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
函数中注册用于实现此目的的事件侦听器。
我们不会深入探讨如何实现选项卡及其功能的逻辑。但是,请记住,我们的自定义 tuts-tab
组件中实现了以下方法,用于在选项卡之间切换:
onTitleClick
: 该方法捕获选项卡标题上的点击事件。它有助于在选项卡面板内切换内容。selectTab
:该函数负责隐藏面板和显示右侧面板。此外,它还负责突出显示所选的选项卡。findFirstSelected
:此方法用于在第一次加载时选择选项卡。selected
:这是一个用于获取所选选项卡的 getter 和 setter。继续,不要忘记定义 disconnectedCallback
。这是自定义元素中的生命周期方法。当自定义元素从视图中销毁时,会触发此回调。这是在应用程序中删除操作侦听器和重置控件的最佳位置之一。但是,回调的范围仅限于自定义元素。在我们的例子中,它将是 tuts-tab
。
最后一步是在 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 サイトの他の関連記事を参照してください。