【JavaScript】DOM要素がresizeイベントを捕捉してくれないときの対処法
更新日:2023/04/06
DOM要素のサイズ変更を捕捉したくてaddEventListener()でresizeイベントを登録したけれど反応してくれませんでした。
調べてみるとresizeイベントは、windowのリサイズ専用のようです。
どうやらDOM要素のサイズ変更は、Resize Observer APIを使用するようです。
そこで今回は、Resize Observer APIの使用方法をお伝えします。
ResizeObserver()の使用方法
Resize Observer APIは、DOM要素のサイズ変更を監視して、コールバック関数で報告するブラウザのAPIです。
まずは、ResizeObserverオブジェクトのインスタンスを作成します。
手順1:インスタンス作成
const resizeObserver = new ResizeObserver( コールバック関数 )
コールバック関数は、DOM要素がリサイズされたときに呼び出される関数です。
コールバック関数については、次項で解説します。
次に、取得したインスタンスのobserveメソッドで、要素のリサイズ監視を開始します。
手順2:監視開始
resizeObserver.observe( DOM要素 , observedBoxオプション );
observedBoxオプションは省略できます。
複数の要素を監視したいときは、要素ごとにobserveメソッドを実行しましょう。
監視を停止するときは、unobserveメソッドまたはdisconnectメソッドを使用します。
備考:監視終了
resizeObserver.unobserve( DOM要素 );
// または
resizeObserver.disconnect();
unobserve()は、要素単位で監視を停止します。
disconnect()は、全ての要素の監視を停止します。
監視の再開は、もう一度observe()を呼び出します。
ResizeObserverのコールバック関数
ResizeObserverのインスタンス生成時に、コールバック関数を引数で渡します。
このコールバック関数は、ResizeObserverEntryの配列を受け取ります。
次のコードは、ResizeObserverでサイズ変更を監視する例です。
コールバック関数の例
const div1 = document.getElementById( "div1" );
const div2 = document.getElementById( "div2" );
const resizeObserver = new ResizeObserver(
entries => {
entries.forEach( entry =>{
const {target,contentRect} = entry;
const name = target === div1 ? "div1" : "div2";
console.log( `${name}の幅が${contentRect.width} 高さが${contentRect.height}に変更されました`);
});
});
resizeObserver.observe( div1 );
resizeObserver.observe( div2 );
監視対象が一つのときはループさせる必要はありませんが、受け取った引数が配列なので[0]を参照します。
const resizeObserver = new ResizeObserver(
entries => {
const {target,contentRect} = entry[0];
・
・
・
});
});
ResizeObserverEntryのプロパティ
コールバック関数に渡されるResizeObserverEntryのプロパティを表にしました。
プロパティは5つあります。
それらはオブジェクトのため、プロパティを持っています。
プロパティ名 | 意味 | プロパティのプロパティ | |
---|---|---|---|
プロパティ名 | 意味 | ||
borderBoxSize | 要素のサイズ | blockSize | 高さ |
inlineSize | 幅 | ||
contentBoxSize | コンテンツのサイズ | blockSize | 高さ |
inlineSize | 幅 | ||
devicePixelContentBoxSize | コンテンツのサイズ (デバイスピクセル単位) | blockSize | 高さ |
inlineSize | 幅 | ||
contentRect | コンテンツのサイズ ※非推奨 | x | 外枠からのx座標 |
y | 外枠からのy座標 | ||
height | 高さ | ||
width | 幅 | ||
top | 上辺のy座標 | ||
bottom | 下辺のy座標 | ||
left | 左辺のx座標 | ||
right | 右辺のy座標 | ||
target | 対象の要素 | 各要素のプロパティ |
要素のサイズは、線幅・パディングを含めたサイズです。
コンテンツのサイズは、線幅・パディングを除いたサイズです。
デバイスピクセル単位は画面上のサイズです。
例えば、ブラウザのズーム機能で100%以外の値を指定しているとき、contentBoxSizeとdevicePixelContentBoxSizeの値が異なります。
contentRectは様々な情報が取得できて使い勝手がいいのですが、初期段階のもので現在は互換のために残されています。
そのため、今後の流れによっては使用できなくなる可能性があります。
できる限り使用しない方がよさそうです。
observedBoxオプションについて
observeメソッドの第二引数は、サイズ変更監視をボーダーボックスまたはコンテンツボックスのどちらで行うのかを指定できます。
observeメソッド
resizeObserver.observe( DOM要素 , observedBoxオプション );
上記の構文のobservedBoxオプションですね。
これは、次オブジェクトを指定します。
{ box : 文字列 }
文字列は、次の3つを使用できます。
実際のところ、連動して変化することが多いのであまり意味がない気がします。
また、連動しないような状況を設定しても通知されたりされなかったりと不明な点が多いです。
例えば、次のようにタイマーでパディングと線幅を変更します。
setTimeout(()=>{
console.log( "padding変更" );
div.style.padding = "5px";
},1000);
setTimeout(()=>{
console.log( "borderWidth" );
div.style.borderWidth = "5px";
},2000);
divは、次のようなタグです。
<div id="div1" style="width:300px;height: 50px;border:1px solid gray;"></div>
この場合、タイマーによりボーダーボックスのサイズが変更されますが、コンテンツボックスは変更されません。
そしてオプション値を設定して実行した、結果は次の通りです。
"content-box"→通知なし。
両方とも、通知されませんでした。
つぎに、divのスタイルに"box-sizing: border-box;"を追加します。
<div id="div1" style="box-sizing: border-box;width:300px;height: 50px;border:1px solid gray;"></div>
この場合、タイマーによりボーダーボックスのサイズが変更なしで、コンテンツボックスが変更されます。
そして結果は、次のようになりました。
"content-box"→通知あり。
両方とも通知されました。
この様子を見ると、コンテンツボックスのサイズ変更を監視している気がしますね。
どちらにしろ、observedBoxオプションがお仕事をしていない印象です。
よくわかりません。
なお今回はFirefox111.0.1とChrome111.0.5563.147で確認しています
更新日:2023/04/06
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。