［Vue3］VueRouterのざっくりまとめ

# 概要
Vue3でSPAを作成する際に利用する記法。
viteでVueをnpmからinitする際に`Vur Router for ... `で`Yes`を選択するとVueRouterがインストールされ、srcディレクトリ内にrouterとviewsが追加される。
この際、routerディレクトリにはindex.tsが作成される。
また、viewsディレクトリはルーティングによって作成されるコンポーネントを格納するフォルダとなる。

```
src
 ├─ assets
 ├─ router
    ├─ index.ts
 ├─ views
 ├─ App.vue
 ├─ main.ts
 ...
```

# @の意味
VueRouterの内容ではないがパスが煩雑になるため、vite.config.tsで設定している@の記法を利用する。
これにより`src`ディレクトリを`@`と記述することができる。
もちろん自身の設定に合わせてルートを設定することも可能。

```vite.config.ts
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
```

# ルーティングの設定
router/index.tsでルーティングの設定を記述する。

## crateRouter()
ルーティングのベースになっているのが`createRouter()`メソッドになる。
createRouter()の引数にはルーティングに関する設定である`history`と`routes`をオブジェクトとして渡す。
`history`はhistoryとhashの2種類があり、それぞれでURLの表示が変わる。
hashモードにするとURLに`#`が入り不自然になるため不採用として詳細の調査も行っていない。
`routes`はルーティング情報配列を指定するプロパティ。

```:表示
● historyモード： http:// localhost: 3000/hoge
● hashモード   ： http:// localhost: 3000/#/hoge
```

## historyオブジェクト
historyモードではリクエストを送信する際に、サーバーがindex.htmlを返すようになっているため、ホスティングサービスを利用する際は、index.htmlを返す設定が必要となるため注意が必要。
また、vueRouterの初期設定で`history:createWebHistory(import.meta.env.BASE_URL)`となっている。
`createWebHistory()`の引数はルーティングのベースパスを表し、`import.meta.env.BASE_URL`はサイトのベースURLで、baseオプションによって決まる。


## routersオブジェクト
routersではサンプルの書き方でルーティング情報を指定する。
`path`にはパスの文字列、`name`にはルーティング名、`component`にはコンポーネントのパスを指定する。
`compnent`にはimportしたコンポーネント名を指定することもできる。
また、ルーティングにパラメーターを指定することもできるがこれはパラメーターを受け取るための記述も必要なため後述する。


```index.ts
// componentにコンポーネントのパスを指定する場合

route: [
	{
		path: "パス文字列",
		name: "ルーティング名",
		component: () => {
			return import("コンポーネントのパス");
		}
	},
	...
];
```

```index.ts
// importしたコンポーネント名を指定する場合

import コンポーネント名 from "@/パス";
...

route: [
	{
		path: "パス文字列",
		name: "ルーティング名",
		component: コンポーネント名
	},
	...
];
```

# ルーティングの記法
各コンポーネントにおけるルーティングについて記述する。
また、routetsについても前項で記録した内容以外の記法がある場合はここで記述する。

## router/index.tsのルーティングを呼び出す
`vue-router`の`RouterView`をimportすし、RouterViewをテンプレートに記述ることでルーティングの設定を呼び出す。

```記法
import { RouterView } from "vue-router";
...

<template>
    <親となるhtmlタグ>
    	<RouterView />
    </親となるhtmlタグ>
</template>
```

## 特定のルーティングを指定する場合
VueRouterでルーティングを行う際は`<a>`タグではな`く<RouterLink>`タグで記述する。（aタグによる遷移を行わないため）
`<RouterLink v-bind:to={name:"ルーティング名"}`で遷移先を指定する。
また、v-bind:toをで遷移先を指定しない場合はrouter/index.tsのルーティング設定がそのまま呼び出される。

```記法
import { RouterView } from "vue-router";
...

<RouterLink v-bind:to="{name:'ルーティング名'}"></RouterLink>
```

## ルートパラメーターの設定

ルーティングでパラメーターを渡したい場合はindex.tsで対象とるルーティング情報に`props`を追記することでパラメーターを設定する必要がある。
そして、パラメーターを送るコンポーネントでパラメーターを指定し、受け取る側のコンポーネントでprops定義を行うことでpropsにルートパラメータが格納される。
また、ルートパラメータはstring型で値が格納されるため数値等の異なる型の場合は、渡す側で型を変換する必要がある。

index.tsのpropstの引数に指定する`routes`は、ルーティングに関する情報が格納されたオブジェクトで、このオブジェクトのparamsプロパティ（routes.params）に、ルートパラメータが格納されている。


```vue:パラメーターを渡すコンポーネント
<script setup lang="ts">
    import { RouterView } from "vue-router";
    ...
</script>

<template>
	<RouterLink v-bind:to="{
        name: 'ルーティング名', 
        params: { パラメーター名: パラメーターの値 } 
        }">
    </RouterLink>
</template>

```

```vue:パラメーターを受け取るコンポーネント
<script setup lang="ts">
    const props = defineProps<
    	{ パラメーター名: パラメーターの型; }
    >();
</script>
```

```index.ts
// パラメーターを渡す場合
import コンポーネント名 from "@/パス";
...

routes: [
	{
		path: "パス文字列/:パラメーター名",
		name: "ルーティング名",
		component: () => {
			return import("コンポーネントのパス");
		},
    	props: (routes) => {
            型変換の処理
            ...
    		return {
    			パラメーター名:パラメーターの値
		};
	}
	...
];
```

### その他パラメーターの書き方
・複数パラメータ
パラメーターを複数設定するのみ。
route.paramsにオブジェクトで格納される。

```:例
パス："/search/:name/:age"
url：http://localhost:3000/search/suzuki/45

・route.params
name: suzuki
age : 45 
```

・省略可能パラメーター
省略可能にするパラメーターの後ろに`?`を記述する。
route.paramsにオブジェクトで格納される。
省略したパラメーターはオブジェクトに格納されない。

```:例
パス："/search/:name/:age?"
url：http://localhost:3000/search/suzuki/45  // フルパス
url：http://localhost:3000/search/suzuki  // 省略

・route.params
name: suzuki
age : 45  // 省略した際はroute.paramsにageはない
```

・可変長パラメーター（必須）
可変長にするパラメーターの後ろに`+`を記述する。
必ず一つはパラメーターが必要で、ないとエラーとなる。
route.paramsには`/`区切りで配列で格納される。

```:例
パス："/search/:tel+"
url：http://localhost:3000/search/11/22/33

・route.params.tel
["11", "22", "33"]
```

・可変長パラメーター（必須ではない）
可変長にするパラメーターの後ろに`*`を記述する。
この場合、パラメーターが必要でない。
route.paramsには`/`区切りで配列で格納される。

```:例
パス："/search/:tel*"
url：http://localhost:3000/search/11/22/33

・route.params.tel
["11", "22", "33"]
```

・404 Not Found

```index.ts
パラメーター名もコンポーネント名はサンプルに合わせる必要はない。
正規表現チェックで既存するルーティング情報以外の全てのURLを受け付けることになる。

routes: [
	{
		path: "/:pathMatch(.*)*",
		name: "NotFound",
		component: () => {
			return import("@/views/NotFound.vue");
		}
	}
];
```




・







## scriptブロック内でルーティングを実行する
VueRouterではスクリプトブロック内でルーティングを制御するためのオブジェクトとして、Routerオブジェクトを取得するuseRouter()関数を提供している。
このRouterオブジェクトのメソッドpush()を利用すると、引数で渡したパスに表示が遷移する。

```vue:記法
<script setup lang="ts">
import { useRouter} from "vue-router";

 関数名 = (): void => {
	useRouter().push({name: "ルーティング名"});
};
</script>
```

### routerオブジェクトの主な関数
<table>
	<tr>
		<td>関数名</td>
		<td>内容</td>
	</tr>
	<tr>
		<td>push()</td>
		<td>指定のパスに遷移</td>
	</tr>
	<tr>
		<td>replace()</td>
		<td>現在のパスに置き換える</td>
	</tr>
	<tr>
		<td>back()</td>
		<td>履歴上の一つ前の画面に戻る</td>
	</tr>
	<tr>
		<td>forward()</td>
		<td>履歴上の一つ次の画面に進む</td>
	</tr>
	<tr>
		<td>go()</td>
		<td>履歴上の指定の画面に進む</td>
	</tr>
</table>

### routerオブジェクトの主なプロパティ
<table>
	<tr>
		<td>プロパティ</td>
		<td>内容</td>
	</tr>
	<tr>
		<td>name</td>
		<td>ルーティング名</td>
	</tr>
	<tr>
		<td>fullPath</td>
		<td>path, hash, queryの全てが含まれた文字列</td>
	</tr>
	<tr>
		<td>path</td>
		<td>パスの文字列</td>
	</tr>
	<tr>
		<td>hash</td>
		<td>ハッシュ（#以降の文字列）</td>
	</tr>
	<tr>
		<td>query</td>
		<td>クエリ情報（？以降の情報）</td>
	</tr>
	<tr>
		<td>params</td>
		<td>パラメーター</td>
	</tr>
</table>

# ルーティングのネスト（親子関係）
ベースのページの下に別のページを表示する場合の書き方。
ベースのルーティング設定のcomponentプロパティの次に`childlen`プロパティを追記する。
childenの中身はroutersの設定と同じ。
ルーティングの呼び出しは`<RouterLink v-bind:to="{name: '子のルーティング名'}">`で特別な内容はない。

```index.ts
routes: [
	{
		path: "パス文字列",
		name: "ルーティング名",
		component: () => {
			return import("コンポーネントのパス");
    	},
		children: [
        	{
        		path: "パス文字列",
        		name: "ルーティング名",
        		component: () => {
        			return import("コンポーネントのパス");
        		}
        	},
            ...
		]
    }
]
```

# 名前つきビュー
同じルーティングで同時に複数のコンポーネントを表示したい場合の記法。、
routersのcomponentプロパティを`components`と記述し、`ルーティング名: コンポーネント`のオブジェクトを渡す。
なお、コンポーネントはimportしたコンポーネントとなる。
また、コンポーネント名なしで呼び出すルーティングには`default`のルーティング名を付する。
ルーティングの呼び出しは`<RouterLink v-bind:to="{name: 'ルーティング名'}">`で特別な内容はない。

```index.ts
import コンポーネントA from "@/views/コンポーネント名A";
import コンポーネントB from "@/views/コンポーネント名B";

routes: [
	{
		path: "パス文字列",
		components: {
            default: コンポーネントA,
            ルーティング名: コンポーネントB,
            ...
        }
    }
]

```

# リダイレクト
routesのプロパティに指定するcomponentを記述せず`redirect`プロパティを指定する。
リダイレクト先を動的に制御する場合はredirectプロパティを値をアロー式で記述する。

```index.ts
import Hoge from "@/views/Hoge.vue";
import Fuga from "@/views/Fuga.vue";
...

routes: [
    // パラメーターの指定なし
	{
		path: "/hoge",
		name: "hoge",
		redirect: { name: "Hoge" }
	},
    // パラメーターの指定あり
	{
		path: "/fuga/:id",
		name: "fuga",
		redirect: (to) => {
			return {
				name: "Fuga", params:{ id: to.params.id }
			}
		}
	},
]
```



# ナビゲーションガード
画面が遷移する前後に処理を挟む機能。

## 対象と関数名等
<table>
	<tr>
		<td>対象</td>
		<td>メソッド</td>
		<td>記述先</td>
	</tr>
	<tr>
		<td rowspan="3">グローバル</td>
		<td>beforeEach</td>
		<td rowspan="4">router/index.ts</td>
	</tr>
	<tr>
		<td>beforResolve</td>
	</tr>
	<tr>
		<td>afterEach</td>
	</tr>
	<tr>
		<td>ルーティングごと</td>
		<td>beforEnter</td>
	</tr>
	<tr>
		<td rowspan="3">コンポーネントごと</td>
		<td>beforeRouterEnter</td>
		<td rowspan="3">各コンポーネント内</td>
	</tr>
	<tr>
		<td>beforeRouterUpdate</td>
	</tr>
	<tr>
		<td>beforeRouterLeave</td>
	</tr>
</table>

## ナビゲーションの呼び出し順序
![スクリーンショット 2023-10-06 030827.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513331/1571858a-e199-6947-6c2b-1467d0965289.png)

## 記法
グローバルガードは、router/index.ts内でcreateRouter()でrouterオブジェクトを取得した後にrouterオブジェクトをexportするまでの間で、routerオブジェクトのそれぞれのメソッドを実行する形で設定する。

各ルーティングごとにナビゲーションガードを設定する場合は、componentプロパティの次に`関数名: (to, from)`で指定する。

各コンポーネントにナビゲーションガードを指定する場合は、vue-routerから`onBeforeRouteENter`等をimportして関数を記述する。

```index.ts
// グローバル
router: [...]
...

router.beforeEach(
	(to, from) => {
		console.log(`--- Global --- beforeEach: to=${to.fullPath};from=${from.fullPath}`);
	}
);

// ルーティングごと

routes: [
	{
		path: "/hoge",
		name: "Hoge",
		component: () => {
			return import("../views/Hoge.vue");
		},
		beforeEnter: (to, from) => {
			console.log(`--- routes --- beforeEnter: to=${to.fullPath};from=${from.fullPath}`);
		}
	}
]

```
```component.vue
<script setup lang="ts">

import { RouterLink, onBeforeRouteEnter } from "vue-router";
...
onBeforeRouteEnter(
	(to, from) => {
		console.log(`--- component --- onBeforeRouteEnter: to=${to.fullPath};from=${from.fullPath}`);
	}
);
<script>

```


# v-bind:toの省略形





# import.meta.env.BASE_URL
あまり重要な内容ではないが調べたので最後に補足。

import.metametaはES2020で導入された仕組みで、モジュールのメタ情報を取得する。
この仕組みによりViteでは環境変数を取得できるようにしており、それがimport.meta.env。
環境変数は作成されたVueプロジェクト全体に対して提供される変数で、これらの変数はプロジェクト直下のvite.config.tsの設定情報が元になっている。
ただし、プロジェクトを作成した際のデフォルトのvite.config.tsには、BASE_URLに関する設定はないため、BASE_URLにあらかじめ設定されているデフォルト値である「/」が採用された状態となっている。