Vue Routerでスクロール位置を保持する

Task

2019年07月30日 18:00

Vue Router は SPA を構築するために、Vue のコンポーネントを適切に切り替えてくれます。

新しくリンクをクリックした時、遷移先が同じコンポーネントを使っていれば異なるコンポーネントだけを描画し直してくれるので、画面下部までスクロールしていたとしても、遷移先でも下部の位置を保持します。

ただこれは従来の Web サイトの挙動と異なるものであり、開発者の意図しない位置の保持や破棄は UX に直結します。

同じコンポーネント同士の遷移であれば以下のようにすることで、ページを進めた時は頁のトップへ、ページを戻ったときは遷移元と同じスクロール位置に移動することが可能です。

const router = new VueRouter({
  mode: "history",
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition;
    } else {
      return { x: 0, y: 0 };
    }
  }
});

同じコンポーネントを使っていればスクロール位置を保持してくれますが、遷移先が異なるコンポーネントで戻るボタンを押した時、位置を保持することができません。

異なるコンポーネントの遷移では Vue の created メソッドが呼ばれるため、コンポーネントが再構成されます。created が呼ばれるということはコンポーネントで保持していたデータを破棄してしまうので、描画された HTML がなくなりページ全体の大きさが ajax で取得される前に戻ってしまいます。

その場合コンポーネントにデータを持たせるのではなく、Vuex を使って Vue 全体のデータの一部として管理することで破棄されなくなります。

戻る遷移を行ったときに Vuex にデータがない場合は created メソッドで呼び出すように分岐することで、データが更新されるのを回避します。

computed: {
  data() {
    return this.$store.state.data;
  },
  created() {
    if (!this.data.length) {
      this.fetchData();
    }
  },
  async fetchData() {
  /* ajaxを呼び出す処理 */
  }
},
p { margin-bottom: 1em; } blockquote p { margin-bottom: initial; } #content ul { padding-left: 40px; } .token.operator { background-color: initial; }

関連記事