Javascript
でページ全体の高さを検知する方法2つ。
想定している状況
Javascriptで目次のハイライト | ikapblogのように、目次をハイライトする場合は、ページ内の章節となる各コンテンツの座標を取得・保持しておくために、初期化関数init()
を実行しています。
しかし、初期化後にページ内の章節となるコンテンツのサイズが変わってしまうとハイライト用の関数は古い座標のリストをもとにハイライトの章節を決定してしまいます。
このため、ページの章節となるコンテンツのサイズが変わった場合は、もう一度init()
を呼ぶなどして、座標リストの更新が必要になります。
このサイズ変更時に更新するという処理について考えていきます。
ちなみにresize
イベントはウィンドウサイズの変更のイベントなのでこれによる検知はできないことには注意しておきます。
また、この記事内では、init()
した後は、update()
で(ハイライトなどを)更新することにします。
ResizeObserverを使う
Experimentalなので対応チェックは必要だけど、ブラウザ任せでコールバックを登録するだけなので簡単です:
const resizeObserver = new ResizeObserver(entries => {
// for文だけどentryはbodyひとつ
for (let entry of entries) {
// 再初期化
init();
}
});
// 監視対象のエントリを追加
resizeObserver.observe(document.body);
実は未確認なので少し調整は必要かもしれません。。MDNドキュメントはこちら: ResizeObserver - Web API | MDN
ドキュメントによると、循環的な依存関係がある時は、ResizeObserver
を利用するべきだそうです。今回は高さを検知して高さを変更するわけではないので、循環的ではないです。
対応しているブラウザを確認した上で使用する必要があります。
イベントリスナーで高さをチェックする
イベントリスナーでupdate()
の更新処理をする場合はこの方法が利用できます。
単純にupdate()
する前に監視する高さの値と以前の更新時の値を比較するだけです:
let lastClientHeight = 0;
document.addEventListener("scroll", () => {
// 折り畳まれたりするとclientHeightは変化するので、直前の値と違ったらinit()し直す
if(lastClientHeight !== document.body.clientHeight) {
init();
// 直前の高さを保持し直す
lastClientHeight = document.body.clientHeight;
}
update();
});
clientHeight
は頻繁には変わらないので、重くはなりにくいはずです。
こちらはExperimental
ではないので、幅広いブラウザで使えます。
おわり
ResizeObserver
はまだ実用していないので、そのうち使ってみたいと思いました。しかし、このくらいの利用方法なら、まだ使うまでもないのかなとも思います。
少し複雑でこれしかないなという時に思いつけるといいなあと思いました。
しかし、まだトータルの高さは変わらないで章節個々の高さが同時に変化した場合には対応できていないことには気を配っておきたいです。 そんなケースはほぼ無いと思うので実装することはないですが、そういう可能性もあるというのは頭の隅っこに置いておきたいです。
以上です。
コメント