私はそのように定義されたカスタム要素を持っています:
class SquareLetter extends HTMLElement {
constructor() {
super();
this.className = getRandomColor();
}
}
customElements.define("square-letter", SquareLetter);
JavaScriptファイルがHTML <head>
タグに含まれている場合、Chromeコンソールはこのエラーを報告します。
キャッチされないDOMException: 'CustomElement'の構築に失敗しました:結果に属性があってはなりません
ただし、JavaScriptファイルが</body>
終了タグの前に含まれている場合、すべてが正常に機能します。どういう理由ですか?
<head>
<script src="js/SquareLetter.js"></script> <!-- here -->
</head>
<body>
<square-letter>A</square-letter>
<script src="js/SquareLetter.js"></script> <!-- or here -->
</body>
エラーは正しいので、どちらの場合も発生する可能性があります。現在、カスタム要素の一部の実装ではこの要件が強制されないため、「幸運」になります。
カスタム要素のコンストラクターは、そのDOMの読み取りまたは書き込みを想定していません。子要素を作成したり、属性を変更したりしないでください。その作業は後で、通常はconnectedCallback()
メソッドで行う必要があります(ただし、要素が削除されてDOMに再度追加された場合、connectedCallback()
は複数回呼び出すことができるため、これを確認するか、disconnectedCallback()
)の変更を元に戻す必要があります。
WHATWG HTML仕様を引用すると、emphasismine:
§4.13.2カスタム要素コンストラクタの要件 :
カスタム要素コンストラクターを作成する場合、作成者は次の適合要件に拘束されます。
super()
へのパラメーターなしの呼び出しは、以降のコードが実行される前に正しいプロトタイプチェーンとthis値を確立するために、コンストラクター本体の最初のステートメントである必要があります。Returnステートメントは、単純な早期復帰(returnまたはreturn this)でない限り、コンストラクター本体内のどこにも現れてはなりません。
コンストラクターは
document.write()
またはdocument.open()
メソッドを使用してはなりません。非アップグレードの場合とは異なり、要素の属性と子は検査しないでください。アップグレードに依存すると、要素の使用が困難になります。
これは、
createElement
またはcreateElementNS
メソッドを使用する消費者の期待に違反するため、要素が属性や子を取得してはなりません。一般に、作業はできる限り
connectedCallback
に委ねる必要があります。特に、リソースのフェッチやレンダリングが関係する作業は特にそうです。ただし、connectedCallback
は複数回呼び出すことができるため、真に1回の初期化作業では、2回実行されないようにガードが必要になることに注意してください。一般に、コンストラクターを使用して初期状態とデフォルト値を設定し、イベントリスナーと場合によってはシャドウルートを設定する必要があります。
これらの要件のいくつかは、要素の作成中に直接的または間接的にチェックされ、それらに従わないと、パーサーまたはDOM APIによってインスタンス化できないカスタム要素が生成されます。これは、コンストラクターによって開始されたマイクロタスク内で作業が行われる場合でも当てはまります。マイクロタスクのチェックポイントは、作成直後に発生する可能性があるためです。
スクリプトをDOM内の要素の後に移動すると、既存の要素が「アップグレード」プロセスを実行します。スクリプトが要素の前にある場合、要素は標準の構築プロセスを通過します。この違いにより、すべてのケースでエラーが表示されるわけではないようですが、これは実装の詳細であり、変更される可能性があります。
CustomComponentを使用したCreatElementの場合も同じ問題に直面します。 superCall関数からconnectedCallback関数を除いて、コンストラクターですべてを削除するまで修正されませんでした。