LoginSignup
8
7

More than 1 year has passed since last update.

Vue2 Composition API でのVue Router3系の使い方

Last updated at Posted at 2021-07-09

Route系の動きを制御する際に、Vue3のComposition APIでは以下のようなやり方をとっています。
しかし、これが使えるのはVue Routerの4.x系以降になります。プロジェクトによっては事情があって3系を使い続けているという場合もあるかと思いますので対処法をまとめました。
また、今後4.x系に移行するぜ!という方にもおすすめできるようにimportfromを以降を書き換えるだけで移行が完了するようにしております。

import { useRouter, useRoute } from 'vue-router'

export default {
  setup() {
    const router = useRouter()
    const route = useRoute()

    function pushWithQuery(query) {
      router.push({
        name: 'search',
        query: {
          ...route.query,
        },
      })
    }
  },
}

対処したいこと

対処したい事柄は基本的に以下二つになるのかなと思います。
両方ともvue-router@3系のままではストレートにsetup()な書き方はできません。

  1. useRouter(), useRoute()が使いたい
  2. ナビゲーションガードはどうすんねん

一つ一つ解消していきます。

1. useRouter(),useRoute()が使いたい

useRouteruseRouteをexportするプラグインを作成しましょう。
pluginsとかcomposableの中にいれて利用しましょう。

router.ts
import {
  ComponentInternalInstance,
  getCurrentInstance,
} from "@vue/composition-api";
import VueRouter, { NavigationGuard, Route } from "vue-router";

/**
 * 現在のインスタンスを取得する
 * setup関数内で呼ばれているかの確認のためにこのメソッドをかませる
 * @returns インスタンス
 */
function getInstance(): ComponentInternalInstance {
  const instance = getCurrentInstance();

  if (!instance) {
    throw new Error(`Should be used in setup()`);
  }

  return instance;
}

/**
 * 4.x系で使えるuseRouterの代替メソッド
 * setup()関数内でのみ使用可能
 * @returns Routerオブジェクト
 */
export function useRouter(): VueRouter {
  // インスタンスにアクセス
  const instance = getInstance();

  // proxyが従来の`this`にあたるコンポーネントインスタンス
  return instance.proxy.$router;
}

/**
 * 4.x系で使えるuseRouteの代替メソッド
 * setup()関数内のみで使用可能
 * @returns Routeオブジェクト
 */
export function useRoute(): Route {
  // インスタンスにアクセス
  const instance = getInstance();

  // proxyが従来の`this`にあたるコンポーネントインスタンス
  return instance.proxy.$route;
}

使うとき

置き場所からimportしたらvue-router@4系での利用方法と全く一緒です。
後々移行しようかな〜と考えているのならばfrom以降を変えるだけなのでラクチン

App.vue
<script lang="ts">
import { defineComponent } from "@vue/composition-api";
import { useRouter, useRoute } from "@/plugins/router.ts"

export default defineComponent({
  name: "xxx",
  setup() {
    const router = useRouter()
    const route = useRoute()

    // この下で好きなように利用
  },
});
</script>

ナビゲーションガードはどうすんねん

onBefoureUpdateなどのナビゲーションガードをsetup()内で利用するのはどうするのか。
同じように、てかさっきと同じファイルに書いてあげます

getCurrentInstance()部分はさっき作成したgetInstance()に置き換えるのがいいと思います。

router.ts
import { getCurrentInstance } from "@vue/composition-api";
import { NavigationGuard } from "vue-router";
import Vue from "vue";
import { ComponentOptions } from "vue/types/umd";

/**
 * ナビゲーションガード系メソッドを生やす為のメソッド
 * @param name ナビゲーションガード名
 * @param callback コールバック
 */
function onHook(
  name: keyof ComponentOptions<Vue>,
  callback: NavigationGuard<Vue>
): void {
  const vm = getCurrentInstance();
  const merge = Vue.config.optionMergeStrategies[name];
  if (vm && merge) {
    const prototype = Object.getPrototypeOf(vm.proxy.$options);
    prototype[name] = merge(vm.proxy.$options[name], callback);
  }
}

/**
 * 4.x系で使えるonBeforeRouteUpdateの代替メソッド
 * @param callback ナビゲーションガードコールバック関数
 */
export function onBeforeRouteUpdate(callback: NavigationGuard<Vue>): void {
  return onHook("beforeRouteUpdate", callback);
}

/**
 * 4.x系で使えるonBeforeRouteLeaveの代替メソッド
 * @param callback ナビゲーションガードコールバック関数
 */
export function onBeforeRouteLeave(callback: NavigationGuard<Vue>): void {
  return onHook("beforeRouteLeave", callback);
}

使い方

使い方は4.x系の公式と同じなのでそちらをみてください

4.x系に移行するには

vue-routerの4系をいれて、

> npm i vue-router@4

from以降を置き換えるだけ
ナビゲーションガードも同じ

App.vue
<script lang="ts">
import { defineComponent } from "@vue/composition-api"; 
// import { useRouter, useRoute } from "@/plugins/router.ts"
// ↓に置き換え
import { useRouter, useRoute } from "vue-router"

export default defineComponent({
  name: "xxx",
  setup() {
    const router = useRouter()
    const route = useRoute()

    // この下で好きなように利用
  },
});
</script>
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7