1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

(備忘録)Javascriptでのonclickの発火タイミング

Last updated at Posted at 2022-02-02

Javascriptを書いていて、あれっ? と思ったことがあったのでメモ。

<details>
  <summary onclick="if(this.parentNode.open){this.innerHTML='折りたたむ'}else{this.innerHTML='展開する'}">展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>

<summary>タグがクリックされるとclickイベントをonclickで拾って、parentNodeである<details>タグがopenであるかを調べ、そうであるなら<summary>の中身を「折りたたむ」に、そうでなければ「展開する」にするコードだが、実際にやってみると…

なんと、想定していたのと真逆の挙動をする。
これはclickイベントが、実際に親要素である<details>openfalseからtrueに変わる(またはその逆)前に発火してしまうからで、実際にはまだopen属性の値が変わっていないのにそれを参照してしまっている(alert()をonclick時に入れてみるとその挙動がわかる)。
暫定的な解決策として、「折りたたむ」と「展開する」を入れ替える。すなわち、

<details>
  <summary onclick="if(this.parentNode.open){this.innerHTML='展開する'}else{this.innerHTML='折りたたむ'}">展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>

こうする。

※2022/2/4追記
コメントからよりいい方法をいただきました。detailsで発生するontoggleイベントを拾うのがよいようです。上のコードを修正するなら、

<details ontoggle="if(this.open){this.querySelector('summary').innerHTML='折りたたむ'}else{this.querySelector('summary').innerHTML='展開する'}">
  <summary>展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>

とすべきでしょう。実際には、三項演算子を使ってもう少し簡潔に、

<details ontoggle="this.querySelector('summary').innerHTML = this.open ? '折りたたむ' : '展開する'">
  <summary>展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>

とできます。

1
0
3

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?