Table of Contents
子孫要素のLoadイベントを単一のElementで拾いたい
問題点
imgタグは自身の読み込みが終わった時にloadイベントを発火させる。
例えばあるコンポーネントを末端までスクロールさせるJavascriptを書きたいが、画像の読み込みは非同期で行われるので、
末端までスクロール→画像が読み込まれ高さが変わる→現在のスクロール位置が末端じゃなくなる
という事象が起こりうる。
ウィンドウ全体の要素を対象に準備が終わったことを検知するなら、windowのloadイベントやdocumentのonChangedReadyStateが存在するが、こいつらはSPAのようなモダンなページでは機能しやがらない。
とはいえ、子要素のimgやらvideoやらに全部loadを書くのもアホらしいので、上記の例ならスクロール処理をしたいコンポーネントに一個loadを書いておきたい気分になる。
特にNuxt(Vue Router)みたいなフレーム上ではぶら下がってるコンポーネントが単離されてたりするので、そのコンポーネントにloadイベントの集約と発火をさせるのはものすごく馬鹿らしい。
サンプル
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>sample page title</title>
</head>
<body>
<div>
<p>↓このDivの全子孫imgのLoadイベントをまとめてフックしたい</p>
<div id="tgt">
<div>
<img src="./img1.jpg" width="200px" />
</div>
<div>
<img src="./img2.jpg" width="200px" />
</div>
<div>
<img src="./img3.jpg" width="200px" />
</div>
</div>
</div>
</body>
<footer>
<script>
const el = document.getElementById("tgt");
el.addEventListener("load", () => {
// 上手く行かない。発火しない
console.log("やっちゃ~");
});
</script>
</footer>
</html>
このサンプルは機能しない。記事タイトルでネタバレしてるんだが、loadイベントはバブリングしないからである。
よってこのように書く必要がある。
<script>
const el = document.getElementById("tgt");
el.addEventListener(
"load",
() => {
console.log("やっちゃ~");
},
true
);
</script>
解説
下記ページに詳しい。
https://ja.javascript.info/bubbling-and-capturing
ようはほとんどのイベントがバブリングするからといって思い込みで書いてるとハマるよという話でした:sob: