LoginSignup
2
1

More than 3 years have passed since last update.

WebComponents の constructor で getAttribute が属性があるのに null を返す時がある件。

Last updated at Posted at 2020-08-21

はじめに

よくJavascriptbodyの閉じタグの前に書くか、それより前で書くなら別ファイルにしてdeferをつけろと言われる。最近この言葉を守らないではまった事例があるのでご紹介。

事例

以下のようにWebComponentsを定義する。

main.js
customElements.define(
    'constructor-attribute'
,   class extends HTMLElement {
        constructor() {
            super()
            this.textContent = this.getAttribute( 'replace' )
        }
    }
)

replaceという名前の属性の値をtextContentにセットするだけのwebComponentsである。

index.html
<constructor-attribute replace =REPLACED>INITIAL</constructor-attribute>
<script src="main.js"></script>

とやると、期待通りブラウザにREPLACEDと表示される。

index.html
<script src=main.js defer></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>

でも期待通りブラウザにREPLACEDと表示される。
ところがscriptdeferをはずして、

index.html
<script src=main.js></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>

とやると、constructorの中のgetAttributenullが帰ってくるので、ブラウザにはINITIALと表示される。

対処

bodyの閉じタグの前に書いてやるか、それより前に書くのなら別ファイルにしてdeferをつける

でもどうしても head で書きたいときとかは、別解?を参照。

別解?

どこにでもおけるようなものを作りたいと思い、次のようにしてみたらちょいハマりした。

main.js
customElements.define(
    'constructor-attribute'
,   class extends HTMLElement {
        static get
        observedAttributes() {
            return [ 'replace' ]
        }
        attributeChangedCallback() {
            this.textContent = this.getAttribute( 'replace' )
        }
    }
)

observedAttributesでウォッチしたい属性を登録しておけば、constructor直後にattributeChangedCallbackが呼ばれるのでここで処理しておけばいい気がしたのでやってみた。

index.html
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>
<script src=main.js></script>
index.html
<script src=main.js defer></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>

上の二つは期待どおりREPLACEDと表示される。

index.html
<script src=main.js></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>

これもうまくいくと思っていたのだが、実際はREPLACEDINITIALと表示される

constructorattributeChangedCallbackは同一のランループで処理されて、そのあと、タグ中の文字列がアペンドされるようだ。chrome,safari,firefox,operaで確認。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1