» TechAcademyの無料体験

【Vue.js】ブラウザバック時にスクロール位置を元に戻す

【Vue.js】ブラウザバック時にスクロール位置を元に戻すJavaScript

Vue.jsを使って、Webサイトを作成していた際に、他の画面に遷移して元の画面に戻ってくると、スクロール位置がページトップに戻ってしまう…

そこで、ブラウザバック時にスクロール位置を元に戻す実装方法について。ライブラリ等は使わずに、実装していきます!

【Vue.js】ブラウザバック時にスクロール位置を元に戻す

他ページ遷移前に、垂直方向にスクロールしたpx数をsessionStorageに保存

他ページに遷移する前に、垂直方向にスクロールしたpx数を window.scrollY で取得し、sessionStorage に保存します。

export default {
  mounted() {
    window.addEventListener("beforeunload", () => {
      sessionStorage.setItem("scrollY", window.scrollY);
    });
  }
}

beforeunload は、ページ移動前に実施されるイベントです。例えば、外部リンクを開く前などに実施されます。

sessionStorage は、ページのセッションが続いている間、データを保存できる領域。似たようなものとして、localStorage があります。

sessionStorage

  • タブやウィンドウを閉じると、データが破棄される

localStorage

  • データの保存期限がなく、タブやウィンドウを閉じてもデータが保持される

元のページに戻ってきた際に、指定の座標までスクロールさせる

戻るまたは進むアクションを行った後に、元のページに戻ってきた場合、指定の座標までスクロールさせます。

export default {
  mounted() {
    (() => {
      let entries = performance.getEntriesByType("navigation");
      entries.forEach((entry) => {
        if (entry.type == "back_forward" && sessionStorage.getItem("scrollY") != null) {
          window.scrollTo(0, sessionStorage.getItem("scrollY"));
        }
      });
    })();
    window.addEventListener("beforeunload", () => {
      sessionStorage.setItem("scrollY", window.scrollY);
    });
  }
}

戻るもしくは進むアクションを行なったかどうかをページ読み込み時に判断する際に、PerformanceNavigationTiming インターフェースを使います。

ナビゲーションの種類には、「navigate・reload・back_forward・prerender」がありますが、今回は、back_forward を指定。

リファレンス:PerformanceNavigationTiming.type – Web APIs | MDN

戻るもしくは進むアクションを行い、scrollYキーがnullではない場合に、元の位置までスクロールさせています!

動的表示させている箇所がある場合、スクロール位置がずれてしまう

静的に表示させている箇所しかない場合は、上記に記載した方法で問題ありませんが、APIを叩いて情報を取得・表示させている箇所などは、その分スクロール位置がずれてしまいます。

そこで、DOMが更新された後に元の位置までスクロールさせるようにします。

export default {
  mounted() {
    this.getItem().then((response) => {
      // 取得したアイテムを変数に入れたりする何かしらの処理

      // DOM更新後に、スクロール位置を移動するようにする
      this.$nextTick(() => {
        let entries = performance.getEntriesByType("navigation");
        entries.forEach((entry) => {
          if (entry.type == "back_forward" && sessionStorage.getItem("scrollY") != null) {
            window.scrollTo(0, sessionStorage.getItem("scrollY"));
          }
        });
      });
    }).catch((e) => {
      console.log(e);
    });

    window.addEventListener("beforeunload", () => {
      sessionStorage.setItem("scrollY", window.scrollY);
    });
  },
  method: {
    async getItem() {
      // アイテムを取得する何かしらの処理
    }
  }
}

DOM更新完了後に、処理を実行する $nextTick() を使用しています。

callback を延期し、DOM の更新サイクル後に実行します。DOM 更新を待ち受けるために、いくつかのデータを変更した直後に使用してください。

API — Vue.js

これで、動的に表示させている箇所があった場合でも、ブラウザバックした際にスクロール位置がずれることはなくなりました!

safariで開いた場合に上述したやり方では上手くいかない

上述した実装方法で、問題なく元のスクロール位置に戻ると思ったのですが、safariでは、元のスクロール位置に戻りませんでした。

原因は、おそらくbfcacheなるものが効いているため、chrome等のブラウザと挙動が変わってくるそう。

そこで、HistoryインターフェースのscrollRestorationプロパティを使って、スクロール位置を復元させる方法にしました。

mounted() {
  if ("scrollRestoration" in window.history) {
    window.addEventListener('load', () => {
      window.history.scrollRestoration = 'auto';
    });
  }
}

これだけでOK!

sessionStorageや$nextTick()を使わずとも、この記述だけで、ブラウザバックした際に、safariの場合でも、元のスクロール位置に戻るようになりました。

コメント

タイトルとURLをコピーしました