JavaScript
dom
EventListener
addEventListener
戻るボタン
0
どのような問題がありますか?

投稿日

ブラウザの戻るボタンで戻ってきた時にもページの初期化を行うJS

概要

あるページから他のページに遷移し、ブラウザの戻るボタンで元のページに戻った時、画面の状態を初期化したいことがあります。
例えば、スイッチ系UIの選択状態を初期状態に戻したい時などです。
その際にも使える初期化コードです。

サンプル

// 初期化を求めるフラグを立てます
let isNeedInit = true;

function initPage() {
  // 初期化フラグが立っている場合にのみ実行します
  if (!isNeedInit) {
    return;
  }
  // 初期化フラグを折ります
  isNeedInit = false;

  /* ページの初期化処理をここに書きます */

};

// ページ離脱の際に初期化フラグを立て直します
window.addEventListener('pagehide', () => {
  isNeedInit = true;
});

// ページ再訪問時に初期化を求めます
window.addEventListener('pageshow', initPage);

// 最初の初期化を実行します
// 必要に応じてDOMContentLoaded等と連携してください
initPage();

解説

上記コードのinitPageに初期化の処理を書くことで、ページの読み込み時や、戻るボタンでページに戻ってきた時に画面の初期化を行うことができます。

windowpageshowイベントはページを訪れた際に発火するイベントです。
以下にMDNの解説を引用します。

  • 最初にページを読み込んだとき
  • 同じウィンドウまたはタブの中で、他のページからそのページへ移動してきたとき
  • モバイル OS で凍結されたページを復元したとき
  • ブラウザーの進む、戻るボタンを利用してこのページに戻ったとき

最初にページを読み込んでいる間、 pageshow イベントは load イベントの後で発生します。

引用元:Window: pageshow イベント - Web API | MDN

注意書きにはpageshowイベントはloadイベントの後で発生と書かれています。
初期化処理を自前で実行した場合、pageshowイベントの発火時にも同じ処理が呼び出されてしまいます。

この重複処理を防ぐためにisNeedInitフラグを利用し、pagehideイベントと連携して、最初の訪問時と他のページから戻ってきた際のみ処理するよう制限しています。

スクリプトの処理順

ページ内のスクリプトは以下の順に処理されます。

  1. <script></script>で読み込まれたスクリプト
  2. Document:readystatechange(document.readyState === 'interactive')
  3. <script src="defer.js" defer></script>で読み込まれた外部スクリプト
  4. Document:DOMContentLoaded
  5. Window:DOMContentLoaded
  6. Document:readystatechange(document.readyState === 'complete')
  7. Window:load
  8. Window:pageshow
ページ内のscript
<script>
function check(e) {
  console.log(e.type, e.currentTarget, document.readyState);
};

// ページ表示関連のイベント
// 発火順の確認のため、あえて逆の順序で記載しています
window.addEventListener('pageshow', check);
window.addEventListener('load', check);
window.addEventListener('DOMContentLoaded', check);
document.addEventListener('DOMContentLoaded', check);
document.addEventListener('readystatechange', check);
</script>
<script src="defer.js" defer></script>
<script src="plain.js"></script>
defer.js
check({ type: 'defer.js', currentTarget: null });
plain.js
check({ type: 'plain.js', currentTarget: null });

上記のHTMLを記述したページを読み込んだ場合、以下の結果になります。

最初にページを表示した際のコンソール
plain.js null loading
readystatechange #document interactive
defer.js null interactive
DOMContentLoaded #document interactive
DOMContentLoaded Window interactive
readystatechange #document complete
load Window complete
pageshow Window complete

他のページに遷移した後、戻るボタンで戻ってきた際の挙動はブラウザによって異なります。

Google Chrome, Microsoft Edge, キャッシュを無効化したブラウザ(最初の訪問時と同じ結果)
plain.js null loading
readystatechange #document interactive
defer.js null interactive
DOMContentLoaded #document interactive
DOMContentLoaded Window interactive
readystatechange #document complete
load Window complete
pageshow Window complete
Firefox, Safari(MacOS), Safari(iOS)(pageshowイベントのみを処理)
pageshow Window complete

この他、<script src="async.js" async></script>で読み込むスクリプトは、上記の処理の間に割り込んで実行されます。
async属性をつけた場合、非同期に、HTMLの処理と並行してファイルの読み込みが行われ、読み込み完了後の実行可能なタイミングで処理されます。
順序の保証はありません。

まとめ

解説は以上です。
pageshow,pagehideのイベントを活用するとブラウザの戻るボタンにも対応した処理を行うことができます。

ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
ユーザー登録ログイン
yukihirog
ユキヒログです。 HTML/CSS/JSを書くのが仕事です。

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
0
どのような問題がありますか?
ユーザー登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
ユーザー登録ログイン
ストックするカテゴリー