あっくんブログ Written by Akihiro Tsuji

Vue3のVue Routerによるルーティング管理

Vue.js プログラミング

こんにちは、あっくんです。先日、ベッドの下を掃除するときにベッドを左手でもちあげて、右手でクイックルワイパーで作業をした瞬間に腰が、あの世行きになりました。つまり腰に負担がかかりすぎて、激痛が走りました。歳とともに、無茶な体の使い方は命取りになると痛感しました。未だ腰は治らずですが、痛みとともに日々バービージャンプと2キロのランニングで鍛えています。今日は、Vue3のVue Routerによるルーティング管理についてやっていきましょう。

複数ページを管理するには?

SPAでは1つのページに表示するコンテンツを入れ替えます。Vue3のフロントエンドフレームワークでは、基本的に「SPA」と呼ばれる形で、Webアプリケーションを構築していきます。SPAとは「Single Page Application」のことで「1つのページだけでできているWebアプリケーションです。」SPAのWebアプリケーションでは、表示の変更は「ページ移動」ではなく、ページ内のコンテンツをダイナミックに変更することで行われています。Vue3で作成するWebページは複数のWebページを作成して移動するのではなく、表示をそれぞれコンポーネントとして定義し、必要に応じてコンポーネントを入れ替えて表示を操作します。

Vue Routerについて

Vue3では、特定のアドレスごとに表示するコンポーネントを割り当てる仕組みを用意されています。アドレスごとに表示などを割り当てる仕組みを「ルーティング」といいます。ルーティングを実現する部品をルーターと呼びます。Vue3における、ルーター機能を提供するのが「Vue Router」というパッケージです。

CDN利用の場合

Vue Routerは、CDN(Content Delivery Network)を利用してスクリプトをダウンロードできます。↓をhead内に追記します。

<script src="https://unpkg.com/vue-router@next"></script>

これでVue3に対応するVue Router4.0.0がロードされるようになります。

npm利用の場合

Vue Routerは、npmでパッケージとして配布されています。この方式でVue Routerをインストールしていきましょう。

まずrouter_appをViteで作成してでサンプルを作っていきましょう。

開発するディレクトリでターミナルに↓のように記述してrouter_appを作って、npmをインストールします。

npm init vite-app router_app

cd router_app
npm install

Vue Routerをインストールしていきましょう。ターミナルで↓を打ち込みましょう。

npm install vue-router

Image from Gyazo

↑npm installでVue Routerをインストール。

2つのコンポーネントを用意する

Vue Routerは、アドレスごとに表示をコンポーネントを割り当てて表示を制御します。ここでは事前に表示するコンポーネントを用意します。 index.htmlにbootstrapを同入して「components」フォルダにあるHelloWorld.vueとHelloJSX.jsxを使って見ていきましょう。

index.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" href="/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vue Router App</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> </head> <body> <h1 class="bg-secondary text-white h4 p-3">Vue3 Vue Router</h1> <div class="container"> <div id="app"></div> </div> <script type="module" src="/src/main.js"></script> </body> </html>
Code language: HTML, XML (xml)

HelloWorld.vue

<template> <div class="alert alert-primary"> <h1>{{ data.title }}</h1> <p class="mt-3 h5">{{ data.msg }}</p> </div> </template> <script> import { ref, reactive } from "vue"; export default { name: "HelloWorld", setup(props, context) { const data = reactive({ title: "HelloWorld", msg: "This is HelloWorld component.", }); return { data, }; }, }; </script>
Code language: HTML, XML (xml)

HelloJSX.jsx

import { ref, reactive } from 'vue' export default { name: 'HelloJSX', setup(props) { const data = reactive({ title:'HelloJSX', msg: 'This is JSX component sample.', }) return () => ( <div class="alert alert-warning"> <h1>{data.title}</h1> <p>{data.msg}</p> </div> ) } }
Code language: JavaScript (javascript)

router.jsの作成

Vue Routerでルーティングを実装するには、srcフォルダの中に「router.js」というファイルを作成し、ルーティングの設定処理を自分で作成していきましょう。

router.js

import { createRouter, createWebHistory } from "vue-router"; import HelloWorld from "./components/HelloWorld.vue"; import HelloJSX from "./components/HelloJSX.jsx"; export const router = createRouter({ history: createWebHistory(), routes: [ { path: "/", name: "index", component: HelloWorld, }, { path: "/jsx", name: "jsx", component: HelloJSX, }, ], });
Code language: JavaScript (javascript)

これがルーティングの処理です。

Vue Routerとコンポーネントのインポート

まず、Vue Routerにある関数をインポートします。ここでは、createRoutercreateWebHistoryという2つの関数をインポートしています。この2つはルーティングの作成に必要な関数です。

import { createRouter, createWebHistory } from "vue-router"; import HelloWorld from "./components/HelloWorld.vue"; import HelloJSX from "./components/HelloJSX.jsx";
Code language: JavaScript (javascript)

createRouterによるRouterの作成

ルーティングを管理する「Router」というオブジェクトを作成する処理です。createRouterという関数を作成します。引数にはオブジェクトを用意して、historyとroutesという値が用意されます。historyはアクセス履歴を管理するオブジェクトです。

createRouter({  history: WebHistory,  routes: ルート情報の配列 }
Code language: CSS (css)

ルート情報について

routesにはルート情報のオブジェクトを配列にまとめたものを値として用意します。

{  path: 割り当てるパス,  name: 名前,  component: 割り当てるコンポーネント }
Code language: CSS (css)

pathはURLのドメイン名より後になります。nameは名前です。componentはインポートしておいたコンポーネントを指定します。

{  path: "/",  name: "index",  component: HelloWorld, }, {  path: "/jsx",  name: "jsx",  component: HelloJSX, },
Code language: CSS (css)

‘/’にHelloWorld、’/jsx’にHelloJSXコンポーネントが割り当てられています。

exportについて

exportを使って、routerオブジェクトを外部から利用できるようにしています。

routerを利用する

作成したrouter.jsをアプリケーションに組み込んでいきましょう。main.jsを修正します。

main.js

import { createApp } from "vue"; import App from "./App.vue"; import "./index.css"; import { router } from "./router"; const app = createApp(App); app.use(router); app.mount("#app");
Code language: JavaScript (javascript)

import { router } from “./router”というようにして、router.jsに用意したrouterオブジェクトをインポートしています。「use」でrouterをアプリケーションに組み込んでいます。これでrouterが使えるようになりましたが、表示できるようになっていません。なので、App.vueを修正する必要があります。

Appを作成する

Appコンポーネントを修正しましょう。2つのコンポーネントの表示を切り替えるボタンと、コンポーネントが表示される専用タグなどを追記します。

App.vue

<template> <div id="app"> <div> <router-link to="/" class="btn btn-primary mx-2"> Go to Top </router-link> <router-link to="/jsx" class="btn btn-warning mx-2"> Go to JSX </router-link> </div> <hr /> <h5>A & B</h5> <router-view name="first"></router-view> <router-view name="second"></router-view> </div> </template> <script> export default { name: "app", created() { console.log("***** App Created! *****"); }, mounted() { console.log("----- App Mounted! -----"); }, data() { return { title: "Router", }; }, }; </script>
Code language: HTML, XML (xml)
Image from Gyazo

↑ターミナルでnpm run devと打ち込み、2つのボタンをクリックすると表示されるコンポーネントが切り替わります。

表示するコンポーネントはVue Routerによって組み込まれるので、Appコンポーネントにcomponentsを用意する必要がないです。

<router-link>と<router-view>

router-linkは表示を切り替えるためのリンクを指定します。

router-link to="パス"

to属性にリンク先のパスを指定します。

router-viewはrouterオブジェクトで割り当ててあるコンポーネントを組み込むためのものです。Vue Routerにより割り当てられているコンポーネントは、このタグに置き換わる形で組み込まれます。このrouter-view>は複数配置する事もできます。

<router-view></router-view>

・・その他のアドレス

ルーターに割り当てていないアドレスにアクセスすると、コンポーネントは表示されません。

例えば、http://localhost:3000/hoge

Image from Gyazo

↑/hogeにアクセスすると何もコンポーネントは表示されません。つまり、ルーティングされていないアドレスにアクセスしても、ページが無いというエラーにらずコンポーネントが表示されないという結果になります。

ページはリロードされているか?

アドレスを切り替えるごとにページはリロードされているのでしょうか?結論、最初にアクセスしたときだけロードされているので、リロードされません。

created() { console.log(" App Created! "); }, mounted() { console.log("----- App Mounted! -----"); },
Code language: JavaScript (javascript)

先程App.vueで記述した↑をデベロッパーツールで見てましょう。

Image from Gyazo

↑デベロッパーツールで2つのリンクをクリックしてコンソールを確認すると、ページは最初にアクセスしたときだけになっています。これがSPAの特徴です。

名前付きビューの利用

1つのパスに複数のコンポーネントを割り当てるにはどうすればよいでしょうか?結論、router-viewタグにname属性で指定の名前のコンポーネントの表示されるようにします。

<router-view name="名前"></router-view>

そのために、router側で「複数のコンポーネントの組み込み」「コンポーネントの名前の指定」を用意しておく必要があります。

router.jsを修正していきましょう。

router.js

import { createRouter, createWebHistory } from "vue-router"; import HelloWorld from "./components/HelloWorld.vue"; import HelloJSX from "./components/HelloJSX.jsx"; export const router = createRouter({ history: createWebHistory(), routes: [ { path: "/", name: "index", components: { default: HelloWorld, first: HelloWorld, second: HelloJsx, }, }, { path: "/jsx", name: "jsx", components: { default: HelloJSX, first: HelloJSX, second: HelloWorld, }, }, ], });
Code language: JavaScript (javascript)

componentsの指定について

コンポーネントを設定するcomponentという値の代わりにcomponentsが用意されています。これは、複数のコンポーネントに名前を付けて設定をするためのものです。

components: { default: デフォルトのコンポーネント, 名前: 割り当てるコンポーネント, …………必要なだけ用意……….. }
Code language: CSS (css)

defaultは、名前を指定しなかった場合に使われるコンポーネントです。

indexルート

components: { default: HelloWorld, first: HelloWorld, second: HelloJsx, },
Code language: CSS (css)

jsxルート

components: { default: HelloJSX, first: HelloJSX, second: HelloWorld, },
Code language: CSS (css)

first,secondは名前です。

App.vueを修正する

App.vue

<template> <div id="app"> <div> <router-link to="/" class="btn btn-primary mx-2"> Go to Top </router-link> <router-link to="/jsx" class="btn btn-warning mx-2"> Go to JSX </router-link> </div> <hr /> <h5>A & B</h5> <router-view name="first"></router-view> <router-view name="second"></router-view> </div> </template> <script> export default { name: "app", created() { console.log("***** App Created! *****"); }, mounted() { console.log("----- App Mounted! -----"); }, data() { return { title: "Router", }; }, }; </script>
Code language: HTML, XML (xml)
Image from Gyazo

↑ボタンをクリックして表示を切り替えると、デフォルトコンポーネントとAとBのコンポーネントが表示されます。

デフォルトのコンポーネントを表示するタグは↓のように用意します。

<router-view/>

「name」属性で名前を指定したビューは↓のように用意します。

<router-view name="first"></router-view> <router-view name="second"></router-view>
Code language: HTML, XML (xml)

パラメータの利用

アクセスするURLのパスにパラメータを用意して値を受け渡すことができます。パラメータを使って値を受け渡すことで、渡されたコンポーネント側で値を利用することができます。

HelloWorld.vueとHelloJSX.jsxを修正して確認していきましょう。

HelloWorld.vue

<template> <div class="alert alert-primary"> <h1>{{ data.title + " [" + name + "]" }}</h1> <p class="mt-3 h5">{{ data.msg }}</p> </div> </template> <script> import { ref, reactive } from "vue"; export default { name: "HelloWorld", props: { name: String, }, setup(props, context) { const data = reactive({ title: "Router", msg: "This is HelloWorld component.", }); return { data, }; }, }; </script>
Code language: HTML, XML (xml)

HelloJSX

import { ref, reactive } from 'vue' export default { name: 'HelloJSX', props:{ name: String }, setup(props) { const data = reactive({ title: 'Router', msg: 'This is JSX component sample.', }) return () => ( <div class="alert alert-warning"> <h1>{data.title} [{props.name}]</h1> <p>{data.msg}</p> </div> ) } }
Code language: JavaScript (javascript)

routerでパラメータを指定する

router.jsのcreateRouter関数を書き換えます。

routes.js

import { createRouter, createWebHistory } from "vue-router"; import HelloWorld from "./components/HelloWorld.vue"; import HelloJSX from "./components/HelloJSX.jsx"; export const router = createRouter({ history: createWebHistory(), routes: [ { path: "/", redirect: "/jsx/taro", }, { path: "/index/:name", name: "index", component: HelloWorld, props: true, }, { path: "/jsx/:name", name: "jsx", component: HelloJSX, props: true, }, ], });
Code language: JavaScript (javascript)

パラメータはパスの指定が必要です。例えばindexのルートの設定を見ると

path: '/index/:name',

この:nameがパラメータです。パラメータは:「名前」という形で記述します。そして

props: true

でパラメータがpropsに属性として渡されるようになります。たとえば、’/index/:name’ならば表示されルコンポーネント側では、props.nameとしてパラメータの値が得られます。

・・リダイレクトについて

{ path: "/", redirect: "/index/taro", },
Code language: CSS (css)

これは、リダイレクトのルート設定です。pathに指定したアドレスにアクセスすると,redirectのアドレスにリダイレクトされます。

Appコンポーネントを修正する

App.vue

<template> <div id="app"> <div> <router-link to="/index/taro" class="btn btn-primary mx-2"> Go to Top </router-link> <router-link to="/jsx/hanako" class="btn btn-warning"> Go to JSX </router-link> </div> <hr /> <router-view></router-view> </div> </template> <script> export default { name: "app", created() { console.log("***** App Created! *****"); }, mounted() { console.log("----- App Mounted! -----"); }, data() { return { title: "Router", }; }, }; </script>
Code language: HTML, XML (xml)
Image from Gyazo

↑ボタンをクリックするとパラメータで渡された名前がコンポーネントに表示されます。

localhost:3000/にアクセスすると/index/taroにリダイレクトされ、Router[taro]と表示されます。

:toの指定について

複数のパラメータを利用するとき「:to」という属性を使ってパスの指定を行います。

:to="{name: '名前', params:{キー: '値'、キー,'値', ……..}}"

nameとparamsという2つの値を用意しています。paramsには、更にパラメータの名前とキーをひとまとめにしたものを用意しています。

App.vue

<template> <div id="app"> <div> <router-link :to="{ name: 'index', params: { name: 'TARO' } }" class="btn btn-primary mx-2" > Go to Top </router-link> <router-link :to="{ name: 'index', params: { name: 'HANAKO' } }" class="btn btn-warning" > Go to JSX </router-link> </div> <hr /> <router-view></router-view> </div> </template> <script> export default { name: "app", created() { console.log("***** App Created! *****"); }, mounted() { console.log("----- App Mounted! -----"); }, data() { return { title: "Router", }; }, }; </script>
Code language: HTML, XML (xml)

ここまで読んでいただいてありがとうございます。
Vue Routerを使うことでリンクを通してのコンポーネントの管理がしやすくなりますね。呼び出したいコンポーネントをrouter.jsに指定して、App.vueのrouter-link :toで紐付ける。SPAなので、リロードされず処理が早いですね。
掌田津耶乃さんのVue.js3超入門で勉強をしています。語りかけるような文章ですごいわかりやすいです。本当におすすめです。