カスタム要素のベスト プラクティス

カスタム要素を使用すると、独自の HTML タグを作成できます。このチェックリストでは、高品質の要素を作成するのに役立つベスト プラクティスについて説明します。

カスタム要素を使用すると、HTML を拡張して独自のタグを定義できます。これらは 非常に強力な機能ですが 低レベルであるため 独自の要素を実装する最善の方法を常に明確にしておきましょう。

快適にご利用いただくために 確認しましょうこの資料には、組織がイノベーションや カスタム要素を追加します。

チェックリスト

Shadow DOM

シャドウルートを作成してスタイルをカプセル化します。

それはなぜでしょうか? 要素のシャドウルートにスタイルをカプセル化すると、機能するようになります。 場所を問わずに機能しますこれは特に、開発者がアプリケーションを 別の要素のシャドウルート内に要素を配置したい場合、この チェックボックスやラジオボタンなどの単純な要素にも適用できます。たぶん Shadow ルート内のコンテンツがスタイルのみになる場合 できます。
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。

コンストラクタ内にシャドウルートを作成します。

それはなぜでしょうか? コンストラクタは、要素の独占的な知識がある場合に使用されます。 他には望ましくない実装の詳細を設定する絶好のチャンス 混同していることがわかります。この処理を後のコールバック(例: connectedCallback は、競合が起きないように保護する必要があることを意味します。 要素が取り外された後、ドキュメントに再度添付される状況です。
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。

要素が作成するすべての子をその Shadow ルートに配置します。

それはなぜでしょうか? 要素によって作成された子は実装の一部であり、 非公開です。シャドウルートを保護しないと、外部の JavaScript が 意図せずしてこれらの子に干渉する場合があります。
<ph type="x-smartling-placeholder"></ph> <howto-tabs> 要素。

<slot> を使用するLight DOM の子を Shadow DOM に投影します

それはなぜでしょうか? HTML の子要素によりコンポーネントのコンポーズ可能な要素が増加するため、コンポーネントのユーザーがコンポーネントのコンテンツを指定できるようになります。ブラウザがカスタム要素をサポートしていない場合、ネストされたコンテンツは引き続き利用可能、表示およびアクセスできます。
<ph type="x-smartling-placeholder"></ph> <howto-tabs> 要素。

:host 表示スタイルを設定する(例: blockinline-blockflex など)。ただし、デフォルトの inline

それはなぜでしょうか? カスタム要素はデフォルトで display: inline であるため、 width または height は無視されます。これは多くの場合 デベロッパーが予想していなかった場合に、 行います。inline ディスプレイが不要になった場合は、 常にデフォルトの display 値を設定する必要があります。
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。

非表示の属性に準拠する :host 表示スタイルを追加します。

それはなぜでしょうか? デフォルトの display スタイルを使用したカスタム要素。例: :host { display: block } は、低い特異性をオーバーライドします <ph type="x-smartling-placeholder"></ph> hidden 属性hidden を設定することを想定している場合は、驚かれるかもしれません。 属性を設定して display: none をレンダリングします。その他の デフォルトの display スタイルに変更し、hidden のサポートを追加 :host([hidden]) { display: none } と一緒に使用できます。
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。

属性とプロパティ

作成者が設定したグローバル属性をオーバーライドしない。

それはなぜでしょうか? グローバル属性とは、すべての HTML 要素に存在する属性です。一部 たとえば、tabindexrole などです。カスタム要素 初期の tabindex を 0 に設定して、キーボードにすることをおすすめします。 焦点を絞ることができますただし、最初に、 要素によってこの値が別の値に設定されています。たとえば tabindex を -1 に設定している場合は、 インタラクティブにできます。
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。これについては ページの作成者をオーバーライドしないでください。

プリミティブ データ(文字列、数値、ブール値)をいずれかの属性として常に受け入れる 定義できます。

それはなぜでしょうか? 組み込みの要素などのカスタム要素は構成可能である必要があります。 構成は、宣言的に、属性を介して、または命令的に渡すことができる できます。理想的には、すべての属性が 対応するプロパティを作成します
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。

プリミティブなデータ属性とプロパティの同期を維持し、 できます。また、その逆も同様です。

それはなぜでしょうか? ユーザーが要素をどのように操作するかはわかりません。かもしれない JavaScript でプロパティを設定し、その値を読み取ることが期待される getAttribute() などの API を使用します。すべての属性に 両方とも反映されるため、 要素を操作できます。つまり、 setAttribute('foo', value) も、対応する値を設定する必要があります。 foo プロパティを逆にすることができます。もちろん例外もあります。 適用できます。高頻度特性は反映されません。 動画プレーヤー内の currentTime。慎重に判断してください。もし ユーザーがプロパティまたは属性を操作すると思われる場合 反映するのは負担になりません
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。これについては 再入荷の問題を回避する

リッチデータ(オブジェクト、配列)のみをプロパティとして受け入れることを目指します。

それはなぜでしょうか? 一般的に、組み込みの HTML 要素の例は リッチデータ(プレーン JavaScript オブジェクトと配列)を 属性です。リッチデータは、代わりにメソッド呼び出しまたは プロパティです。リッチデータを JSON データとして受け入れることには、明らかに 属性: 大きなオブジェクトを文字列にシリアル化すると、コストがかかる可能性があります。 この文字列化プロセスでオブジェクト参照が失われます。対象 たとえば、別のオブジェクトへの参照を持つオブジェクトを文字列化すると、 場合、これらの参照は失われます。

リッチデータのプロパティを属性に反映させない。

それはなぜでしょうか? リッチデータのプロパティを属性に反映させると、不必要に費用がかかる。 同じ JavaScript オブジェクトをシリアル化/逆シリアル化する必要が ありますただし、 この機能でしか解決できないユースケースや 避けることをおすすめします。

要素の前に設定された可能性のあるプロパティを確認することを検討してください。 アップグレードされます。

それはなぜでしょうか? 要素を使用するデベロッパーが要素にプロパティを設定しようとする可能性があります。 呼び出すことができます。これは特に、 開発者は、コンポーネントの読み込み、それらのスタンプの そのプロパティをモデルにバインドします
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。詳しくは、 プロパティを遅延状態にする

クラスを自己適用しないでください。

それはなぜでしょうか? 状態を表現する必要がある要素は、属性を使用して表現する必要があります。「 通常、class 属性は その要素に自分で書き込みを行うと、 開発者のクラスを踏み台にしています。

イベント

内部コンポーネントのアクティビティに応じてイベントをディスパッチします。

それはなぜでしょうか? コンポーネントのプロパティは、 たとえば、タイマーやアニメーションのレスポンスが リソースの読み込みが完了したときに発生します。イベントをディスパッチし、 コンポーネントの状態が変化したことをホストに通知します。 異なります

ホストによるプロパティの設定に応じてイベントをディスパッチしない 。

それはなぜでしょうか? プロパティの設定に対するイベントのディスパッチは不要 (ホストは、設定したばかりの状態なので、現在の状態を把握しています)。イベントをディスパッチする ホスト設定に応じてプロパティによってデータの無限ループが発生する可能性がある 構築されています
<ph type="x-smartling-placeholder"></ph> <howto-checkbox> 要素。

説明動画

ページの作成者をオーバーライドしない

要素を使用するデベロッパーは、 初期化されます。たとえば、ARIA role やフォーカス可能性を次のように変更します。 tabindex。これらのグローバル属性とその他のグローバル属性が設定されているかどうかを確認します。 確認してください

connectedCallback() {
  if (!this.hasAttribute('role'))
    this.setAttribute('role', 'checkbox');
  if (!this.hasAttribute('tabindex'))
    this.setAttribute('tabindex', 0);

プロパティを遅延状態にする

デベロッパーが要素の前にプロパティを設定しようとしたり、 定義が読み込まれました。これは特に、開発者が コンポーネントの読み込みとページへの挿入を処理するフレームワークです。 それらのプロパティをモデルにバインドします

次の例では、Angular はモデルの引数を宣言的に isChecked プロパティをチェックボックスの checked プロパティに追加します。定義が、 Howto-checkbox を遅延読み込みしていた場合、Angular が 要素がアップグレードされる前に確認されたプロパティ。

<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>

カスタム要素では、いずれかのプロパティに属性があるかどうかを確認することで、このシナリオに対処する必要があります。 インスタンスにすでに設定されているからです。<howto-checkbox> _upgradeProperty() というメソッドを使用して、このパターンを示しています。

connectedCallback() {
  ...
  this._upgradeProperty('checked');
}

_upgradeProperty(prop) {
  if (this.hasOwnProperty(prop)) {
    let value = this[prop];
    delete this[prop];
    this[prop] = value;
  }
}

_upgradeProperty() は、アップグレードされていないインスタンスから値を取得して、削除します。 カスタム要素独自のプロパティ セッターがシャドーイングされないように、プロパティを無効化します。 これにより、要素の定義が最終的に読み込まれたときに、すぐに 正しい状態を反映します。

再入荷の問題を回避する

attributeChangedCallback() を使用して、状態をモデルに 次のようなプロパティがあります。

// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
  if (name === 'checked')
    this.checked = newValue;
}

ただし、プロパティ セッターが属性値も反映されている場合、これにより無限ループが生じることがあります。 作成します。

set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    // OOPS! This will cause an infinite loop because it triggers the
    // attributeChangedCallback() which then sets this property again.
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}

別の方法としては、プロパティ セッターが属性に反映されるようにする方法もあります。 その属性に基づいてゲッターが値を決定します。

set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}

get checked() {
  return this.hasAttribute('checked');
}

この例では、属性を追加または削除すると、プロパティも設定されます。

最後に、attributeChangedCallback() を使用して副作用を処理できます。 適用できます。

attributeChangedCallback(name, oldValue, newValue) {
  const hasValue = newValue !== null;
  switch (name) {
    case 'checked':
      // Note the attributeChangedCallback is only handling the *side effects*
      // of setting the attribute.
      this.setAttribute('aria-checked', hasValue);
      break;
    ...
  }
}