前提
端末: MacBook Pro
OS: macOS Catalina 10.15.7
Node.js: v12.18.3
Vue.js: v2.6.11
Vue-CLI: v4.5.13
Node.js, yarn, Vue 既にインストール済み
Vue-CLI を利用して、プロジェクトを作成済み
Vue Router とは
Vue.js を利用した SPA(シングルページアプリケーション)の構築において、ルーティング制御をするための公式プラグインのことを指す
SPA とは
複数ページではなく、単一のページで構成された web アプリケーションまたは web サイトのことを指す
初めに 1 つの html を読み込み、以後は Ajax で情報を動的にページを更新させる
新しい情報を読み込む際にページ遷移を行う必要がないため、ネイティブアプリのような動作をすることが可能
セットアップ
yarn でインストール
(Vue Cli でプロジェクト作成した場合だと、既にインストール済みの可能性あり)
$ yarn add vue-router
package.json に定義されているか確認
{
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.5.1"
},
}
簡単に SPA を作成する
router.js を /src 配下に作成する
(表示用のコンポーネントは適時作成)
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from './components/Home'
import Foo from './components/Foo'
import Bar from './components/Bar'
// モジュールとして使用する場合に必要
Vue.use(VueRouter)
// ルーターインスタンスを作成
export default new VueRouter({
// デフォルトの挙動では url に # が含まれている(例: ~/#/foo)
// history モードを指定することで url から hash を取り除くことが可能
mode: 'history',
// ルート定義において、各ルートは 1 つのコンポーネントとマッピングされる必要がある
// 適時コンポーネント作成をお願いします => <template><div>HOME</div></template>
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/foo',
name: 'foo',
component: Foo
},
{
path: '/bar',
name: 'bar',
component: Bar
},
]
})
main.js を修正
import Vue from 'vue'
import App from './App.vue'
// 3 で作成した router モジュール
import router from './router'
Vue.config.productionTip = false
// root となる Vue インスタンスを作成する際にルーターを定義する
// 他のコンポーネントで this.$router と定義をすることで VueRouter にアクセス可能となる
new Vue({
router,
render: h => h(App),
}).$mount('#app')
App.vue の template の中身を修正
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<h1>Hello Vue.js Hands on!</h1>
<div>
<h2>SPA</h2>
<!-- SPA を実現させるためには router-link コンポーネントを使用する -->
<!-- リンク先を to プロパティに指定する -->
<!-- router-link タグは a タグとしてレンダリングされる -->
<router-link to="/">Go to Home</router-link><br>
<router-link to="/foo">Go to Foo</router-link><br>
<router-link to="/bar">Go to Bar</router-link>
</div>
<div>
<h2>NOT SPA</h2>
<a href="/">Go to Home</a><br>
<a href="/foo">Go to Foo</a><br>
<a href="/bar">Go to Bar</a>
</div>
<div>
<h2>CONTENTS</h2>
<!-- ルートとマッチしたコンポーネントが描画される -->
<router-view />
</div>
</div>
</template>
下記のコマンドを叩いてローカルサーバーを起動
$ yarn serve
SPA の a リンクを押下しても、リロードが走らない(SPA)ことが確認可能
NOT SPA の a リンクをクリックすると通常のリクエスト、レスポンスとなり、リロードが走る
ルーターへのアクセス
this.$route
でルーティング情報にアクセスすることが可能
this.$router
でルーティング全体の情報にアクセスすることが可能
下記の処理は、 js の処理内で使用することが多い
// router-link で定義した a リンクをクリックすることと同義
this.$router.push('/home')
動的ルートマッチング
router.js に下記のパス情報を追加する
{
// 「:~」と定義することで、パラメーターを含むルーティングを設定可能
path: '/user/:id',
name: 'user',
component: User
}
作成した User.vue に定義する
<template>
<div>
USER<br>
<!-- url が含むパラメーターは $route.params.~ で取得可能 -->
{{ $route.params.id }}
</div>
</template>
名前付きルート
router.js における routes オプションの中でルートに名前を付与することが可能
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/foo',
name: 'foo',
component: Foo
},
{
// 「:~」と定義することで、パラメーターを含むルーティングを設定可能
path: '/user/:id',
name: 'user',
component: User
}
]
router-link コンポーネントの to プロパティにオブジェクトを渡すことが可能
<router-link :to="{ name: 'user', params: { id: 123 }}">Go to User 123</router-link>
リダイレクト
router.js における routes の設定にてリダイレクトが可能
下記の記述で、 /foo から /bar にリダイレクトさせる
routes: [
{
path: '/foo',
redirect: '/bar',
}
]
上記で定義した名前付きルートに対してもリダイレクトが可能
routes: [
{
path: '/foo',
redirect: { name: 'bar' },
}
]
function を使用した動的なダイレクトも可能
routes: [
{
path: '/foo',
redirect: () => {
alert('リダイレクトします')
return '/bar'
},
]
ネストされたルーティング
下記のようなルーティングだった場合の実現方法
~/user/:id
~/user/:id/profile
~/user/:id/posts
router.js を修正する
{
path: '/user/:id',
name: 'user',
component: User,
children: [
{
// ~/user/:id/profile がマッチした際に User コンポネ内の router-view 内部で描画される
path: 'profile',
component: UserProfile
},
{
// ~/user/:id/posts がマッチした際に User コンポネ内の router-view 内部で描画される
path: 'posts',
component: UserPosts
}
]
}
User.vue を修正する
<template>
<div>
USER
<!-- ネストされたコンポネは下記の router-view にて描画される -->
<router-view />
</div>
</template>
スクロール位置を制御する
デフォルトだと SPA でページを表示した際に、スクロール位置が固定されている。
VueRouter のインスタンスを生成する際に下記の定義を追加することで、
ブラウザらしい挙動になる。
export default new VueRouter({
.
.
scrollBehavior (to, from, savedPosition) {
// ブラウザの「戻る/進む」ボタン押下時には、スクロール位置が固定される(savedPostion に定義されている)
return savedPosition ? savedPosition : { x: 0, y: 0 }
},
.
.
}