30代からのプログラミング学び直し!

10年エンジニアやってるけどいまだになんもわからん

History: pushState() した後はpopstateイベントでブラウザバックに対応する

前回の記事の内容では不十分だったので、その続き。 (すぐに記事にしたかったのに色々あって1ヶ月も空いてしまった)

aya-cat-g-tech.hatenadiary.jp

非同期でページング処理をしている画面にて、History: pushState()を使ってURLにページ番号を付与するようにしましたが、ブラウザバックのことを考慮していませんでした。 何もしないでいると、ブラウザバック時にはブラウザのアドレスバーは変化するが、画面は何も変わらないということになってしまいます。

なので、popstateイベントを検知するようにしてブラウザバックに対応します。

Window: popstate イベント - Web API | MDN

ページングのコールバック関数内でhistory.pushState()を設定する(おさらい)

clickCallback(pageNum) {
      let url = new URL(location.href);
      url.searchParams.set('page', pageNum);
      history.pushState(
        null,
        '',
        `${url.pathname}?${url.searchParams.toString()}`
      );
},

popstateのイベントリスナーを設定しておく。Vue.jsだったらcreated()内とかに書く。 以下コードはVue.jsで、this.currentPageに現在のページ番号を設定しリアクティブに描写し直しています。

window.addEventListener('popstate', () => {
      let page = new URLSearchParams(location.search).get('page');  // パラメータからページ番号取得
      this.currentPage = Number(page) || 1;
      if (this.isEmpty(this.list[this.currentPage])) {
        // リロードを挟んだ時などを考慮して、結果がなければ非同期で取得する処理も書いておくと良い
      }
});

ページ番号はURLのパラメータから取得するようにしました。 以下のように、history.pushState()の第1引数で状態を渡すこともできるようですが、これだとブラウザバックの途中でリロードを挟まれた時などにうまく動作しなかった(確か…前のことなのであまり覚えていない…)ので、パラメータから取得するのが一番確実な感じがしました。

リロードとかされるとうまくいかなかった例(実装に問題があるのかもしれないが)

// ページング時の処理
clickCallback(pageNum) {
      let url = new URL(location.href);
      url.searchParams.set('page', pageNum);
      history.pushState(
        { page: pageNum },
        '',
        `${url.pathname}?${url.searchParams.toString()}`
      );
},
// イベントリスナー
window.addEventListener('popstate', (event) => {
      this.currentPage = event.state.page;
});