ブラウザバックで戻ったときは通常はキャッシュされたページが表示されます。ですが、それだと都合が悪いケースがたまにあります。
先日も「ブラウザバックで戻ったときもページ読み込み時と同じようにアニメーション動かして欲しい」という要望をうけました。その際、いろいろ試行錯誤したので防備録として残しておこうと思います。
ロジックとコード
ロジックとしては下記のよう流れになります。
- ページ読み込み時にブラウザバックかどうか判定
- ブラウザバックの場合はアニメーションのクラスを削除してまた付け直す
で、下記のようなコードになります。is-animated
クラスの有無でアニメーションが切り替わるという前提になります。
const target = document.querySelectorAll('.target-element');
window.addEventListener('pageshow', function(event) {
if (event.persisted || performance.getEntriesByType("navigation")[0].type === 'back_forward') {
target.forEach(function(element) {
element.classList.remove('is-animated'); // クラスを一旦削除
setTimeout(function() {
element.classList.add('is-animated'); // 再度クラスを付与
}, 250);
});
} else {
// 通常のページ読み込み時
target.forEach(function(element) {
element.classList.add('is-animated');
});
}
});
ここまでたどり着くまでに、いろいろハマりました・・・。
イベントはpageshowを使う
まず、どのイベントを利用するかですが、load
はページ読み込み時に発火しますが、ブラウザバックでキャッシュされたページを表示する場合は読み込みではないので発火しません。
代わりにpageshow
を使います。pageshow
はページが表示され時に発火するので読み込みでもキャッシュ表示でもどちらでも使うことができます。
これで第一段階はクリア。
ブラウザバックかどうかの判定にevent.persisted が上手く動かない
一番困ったのがここです。
検索で調べるとブラウザバックだとevent.persisted
がtrueになるという情報がでてくるのですが、これだけでは上手く判定されないことがあります。私が調べたときはPCのブラウザはOKでしたがiOSのブラウザでは正しく判定されませんでした。
さらに深掘りすると stackOverflow で素晴らしい記事がありました。WebKit系はevent.persisted
の挙動がどうもバグっぽいようです。
その記事にあったコードが下記です。
performance.getEntriesByType("navigation")[0].type === 'back_forward'
perfomanceはウィンドウの情報をいろいろ取得できるインターフェースらしいのですが、それを使うと、いろいろな情報が取得できるようです。
上記コードの場合はnavigation
というオブジェクトのtype
プロパティがback_forwad
かどうかを判定しています。
FireFoxではこちらは上手く動かないそうですが、逆にevent.persistedは正しく判定されるので、この両方を書いておけばOKということになります。
これで読み込みかブラウザバックか判定できるようになりました。
クラスの付け外し処理
最後にアニメーショをやり直す処理ですが、単純にクラスを削除して追加する処理を書くと上手く動きません。
今回は少し間があった方がよいぐらいだったので、setTimeoutでクラスを付与するタイミングを調節することで対応しました。要件によって時間を調整するとよいと思います。
これを利用すれば、例えばブラウザバックではフォームを強制的にリセットする、というようなことにも応用できます。
コメント
この記事へのコメントはありません。