くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

vue-routerだけでページ内のsmooth-scrollを実現する

ページ内の移動には、vue-scrolltoを使ってたけど、
vue-routerだけでもいけそうだったのでためしてみた(*´ω`*)

ちなみに、Nuxt2での設定。

簡単な使い方

nuxt.config.tsrouter.scrollBehaviorに設定を加えると、
いろいろ振る舞いを変えれるらしい(*´ω`*)

// nuxt.config.ts
import { NuxtConfig } from "@nuxt/types";
const config: NuxtConfig = {
  router: {
    scrollBehavior(to, from, savedPosition) {
      if (to.hash) {
        return { selector: to.hash, behavior: 'smooth' }
      }
    }
  }
};

export default config;

注意点

上の例だけでよさそうだと思ったけど、
実際使ってみると、いろいろ調整が必要だった。。

  • ページ遷移アニメーションをつけている場合、setTimeoutなどを使ってすこし待つ必要がある
  • idが日本語などの場合、hashがエンコードされているため、デコードする必要がある
  • ヘッダなどをfixedなどにしている場合、オフセットを設定する必要がある

最終的な設定

最終的にはこんな感じ(*´ω`*)
型定義が無いのもあるので、いくつか手動で用意。。

// nuxt.config.ts
import { NuxtConfig } from "@nuxt/types";

const config: NuxtConfig = {
  /*
   * Router configuration
   */
  router: {
    scrollBehavior(to, from, savedPosition) {
      type Pos = { x: number; y: number };
      type Pos2 = { selector: string; offset?: Pos; behavior?: ScrollBehavior };
      type PosResult = Pos | Pos2 | void;

      const getPos = (to: Route, from: Route, pos: Pos | void): PosResult => {
        // idが日本語の場合は、デコードが必要
        const hash = decodeURIComponent(to.hash);
        // ヘッダをfixedやstickyにしている場合は、オフセットをつける
        const offset: Pos = { x: 0, y: 48 };
        // 遷移先がハッシュの場合
        if (hash) return { selector: hash, behavior: "smooth", offset: offset };
        // 遷移先にハッシュがなく、同一ページの場合
        else if (to.name == from.name && from.hash) {
          return { selector: "body", behavior: "smooth", offset: offset };
        }
        // 保存したPositionがある場合
        else if (pos) return pos;
        // デフォルト
        else return { x: 0, y: 0, offset: offset };
      };

      // 同一ページの場合は、すぐにスクロールする
      if (to.name == from.name) return getPos(to, from, savedPosition);
      // 異なるページの場合は、遷移アニメーションがあるので、少し待ってからスクロールする
      else {
        return new Promise((resolve, _) =>
          setTimeout(() => resolve(getPos(to, from, savedPosition)), 400)
        );
      }
    }
  },
};

export default config;

以上!! 便利(*´ω`*)
細かい設定はできないけど、シンプルなのであれば、これでいいかも(*´ω`*)

参考にしたサイト様