Vue.js 超入門3.4+ 第12章 Vue Router
https://scrapbox.io/files/66812ac240163e001db7bdf2.png
第12章 Vue Router
Vueは基本的にSPA(シングル・ページ・アプリケーション)だが、リンクで他のページに遷移することもできる
それを実現するには、Vue の公式ルータである「Vue Router」を使用する
学ぶこと
Vue Router
リアクティブの監視(Watch)
12.1 インストール
code:sh
npm install vue-router@4
yarn add vue-router@4
12.2 Vue Router を使うための準備をする
src 配下に router フォルダ- index.ts ファイルを作成する(Vue Router を使うための設定ファイル)
code:ts
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: []
});
export default router;
main.tsに Vue Router を使うための設定
code:ts
import './assets/main.css';
import { createApp } from 'vue';
import App from './App.vue';
import router from './router'; // 追加
createApp(App).use(router).mount('#app'); // use(router)を追加
App.vueのメインのコンテンツを<router-view /> で置き換える
code:ts
<template>
<div class="wrap">
<TheHeader />
- <main class="main"><MainTodo /></main>
+ <main class="main"><router-view /></main>
<TheFooter />
</div>
</template>
ここからはページ単位でアプリケーションを作成していくことになるので、src/配下にviewsまたはpagesというページの置き場所を作る
12.3 ルートを設定する
準備はできたので、ルートを設定して画面を表示できるようにする
ルートを設定することで、<router-view /> が、それに紐づいたページに変わる
src/router/index.tsにルートを追加した
code:typescript
import { createRouter, createWebHistory } from 'vue-router';
import MainTodo from '@/views/MainTodo.vue';
import About from '@/views/About.vue';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'top', // nameを使う場合は名前が重複しないようにする
component: MainTodo
},
{
path: '/mainTodo',
name: 'mainTodo',
component: MainTodo
},
{
path: '/about',
name: 'about',
component: About
}
]
});
12.5 遅延ローディングルートとは
ビルドしてみる
code:sh
npm run build
yarn build
コマンド実行後、distフォルダが作られ、assetsの中にjsファイルが生成される(コンパイルされたもの)
https://scrapbox.io/files/684e2523265d5168ea56ee5e.png
アプリが大きくなると、このjsファイルも肥大化し、最初の読み込みに時間がかかるようになってしまう
それを防ぐために、ページごとにjsファイルを分割し、そのページを訪れたタイミングで読み込む
→ 遅延ローディングルート と言う
code:js
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'top', // nameを使う場合は名前が重複しないようにする
component: MainTodo
},
{
path: '/mainTodo',
name: 'mainTodo',
component: MainTodo
},
{
path: '/about',
name: 'about',
component: () => import('@/views/About.vue') // 変更
}
]
});
このように直してビルドすると、distの下にAbout.xxxxx.jsファイルが作られる
index.jsからAboutページのJSが分離された
Aboutページに遷移したら読み込まれる
SPAで問題になりがちな初回ロードの重さが緩和される
12.6 404ページに誘導する
code:typescript
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'top', // nameを使う場合は名前が重複しないようにする
component: MainTodo
},
{
path: '/mainTodo',
name: 'mainTodo',
component: MainTodo
},
{
path: '/about',
name: 'about',
component: () => import('@/views/About.vue')
},
{
path: '/:pathMatch(.*)*', // 存在しないアドレスにマッチする指定
name: 'notFound',
component: () => import('@/views/NotFound.vue')
}
]
});
12.7 リンクからページ遷移する
リンクから遷移するには
Vue Routerの遷移は、内部リンクの場合、<a>タグでなく<router-link>を使う
<a>タグでも遷移はできるが、遷移するたびにページ全体を再読み込みする
<router-link>は、<router-view />内が置き換わるだけなので高速に遷移することができる
code:typescript
<template>
<div class="wrap">
<TheHeader />
<nav>
<router-link to="/">Todo</router-link>
<router-link to="/about">About</router-link>
</nav>
<main class="main"><router-view /></main>
<TheFooter />
</div>
</template>
12.8 プログラムからページ遷移する
@clickイベントでBlogページへ移動する
router.push()で遷移させることができる
code:typescript
<script setup lang="ts">
import { useRouter } from 'vue-router';
import TheHeader from '@/components/TheHeader.vue';
import TheFooter from '@/components/TheFooter.vue';
const router = useRouter();
const goBlog = () => {
router.push('/blog');
};
</script>
<template>
<div class="wrap">
<TheHeader />
<nav>
<router-link to="/">Todo</router-link>
| <router-link to="/about">About</router-link> | <span @click="goBlog">Blog</span>
</nav>
12.9 動的ルート
blog/1、blog/2のように、記事ごとにURLの部分が変わる場合がある
このような場合は、routesの設定を特別なものにする → パスの動的となる部分に「:」コロン付きの名前を当てる
code:typescript
{
path: '/blog/:id',
name: 'blog',
component: () => import('@/views/Blog.vue')
}
code:html
<router-link to="/">Todo</router-link>
| <router-link to="/about">About</router-link>
| <span @click="goBlog">Blog</span>
| <router-link to="/blog/1">Blog1</router-link>
| <router-link to="/blog/2">Blog2</router-link>
nameオプション
使い方はto属性にアドレスで指定したところをnameにする
nameのpathがルートに設定される
code:html
// template
<router-link :to="{ name: 'blogId', params: { id: 1 } }">Blog1<router-link>
// script
router.push({ name: 'blogId', params: { id: 1 } })
12.10 パラメータ渡し
ブログのアドレスとして末尾にIDを追加した
アドレスからIDを取得して、そのIDの記事を取得したりする
URLのパラメータを取得するには、useRoute()を使う
code:sh
<script setup lang="ts">
import { ref } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
// routes で設定した :id と同じ名前を指定する
const id = ref(route.params.id);
</script>
<template>
<h1>blog page</h1>
<p>blog id = {{ id }}</p>
</template>
しかし、上記の例だと/blog id = に続く文字は1か2しか表示されない
同じコンポーネントインスタンスを再利用しているため
コンポーネントのライフサイクルフックが呼ばれていない
12.11 リアクティブの監視
watch APIと言う解決策
watchは、特定の値を監視することができる
アドレス(route)を監視し、それの変化をキャッチすれば処理を行うことができる
下のコードは、初回だけBlogコンポーネントが呼び出され、その後、同じコンポーネントだったら初回のコンポーネントを利用する
watchで特定の値を監視することで変化を捉えて、idを変化させる
code:typescript
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
// routes で設定した :id と同じ名前を指定する
const id = ref(route.params.id);
console.log(watch外: ${id.value}); // 追加
// 追加↓
watch(route, () => {
id.value = route.params.id;
console.log(watch内: ${id.value});
});
</script>
今度は切り替わる
https://scrapbox.io/files/685c9a4d6684e65607efa7f0.png