Javascriptを書いていて、あれっ? と思ったことがあったのでメモ。
<details>
<summary onclick="if(this.parentNode.open){this.innerHTML='折りたたむ'}else{this.innerHTML='展開する'}">展開する</summary>
<!-- ここにいろいろな内容... -->
</details>
<summary>
タグがクリックされるとclick
イベントをonclick
で拾って、parentNode
である<details>
タグがopen
であるかを調べ、そうであるなら<summary>
の中身を「折りたたむ」に、そうでなければ「展開する」にするコードだが、実際にやってみると…
なんと、想定していたのと真逆の挙動をする。
これはclickイベントが、実際に親要素である<details>
のopen
がfalse
から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>
とできます。