【Vue2】 Vue Routerの機能の整理

# Vue Routerを使う

- インストール

```bash
npm i vue-router
```

- vue-routerの設定を行う（ルーティングとコンポーネントの紐づけ） ( /src/router.js )

```js
import Vue from 'vue';
import Router from 'vue-router'
import Home from '/views/Home.vue' 
import About from '/views/About.vue'

Vue.use(Router) // プラグイン（どこでも使える機能）を適用するために記載

export default new Router({
    routes:[
        {
            path:'/',  			// URL 
            component:'Home'	// 上記URLのときに表示するコンポーネント
        },
        {
            path: '/about',
            component:'About'	
        }
    ]
})
```

- routerをVueのグロバルコンポーネントで適用する( /src/main.js )

```js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
    router,
    render: h => h(App)
}).$mount("app")
```

- 表示個所にrouter-viewを用意する (/src/App.vue)

```vue
<template>
	<div>
    	<router-view></router-view>
	</div>
</template>
```



# さまざまな機能

## URLの#を消す（mode:history)

デフォルトは`mode:hash`で、＃がついている。`mode: history` とすることで、URLの＃を消すことができる。

( /src/router.js 一部抜粋)

```js
export default new Router({
    mode: 'history',
    routes:[ ... ]
})
```



## URLを切り替える (router-link to="/")

`<router-link to="リンク先">`とすることで、指定したリンク先に遷移するリンクができる (/src/App.vue)

``` vue
<template>
	<div>
    	<router-link to="/"> HOME </router-link>
        <router-link to="/about"> ABOUT </router-link>
        <router-view></router-view>
    </div>
</template>
```

`to`属性はv-bindでバインディングできる。



## URLに応じてクラスを変える (active-class)

`active-class="クラス名"`をすることでリンクを含むURLの時のみクラスが適用される。`exact`をつけることで完全一致するURLの時のみ適用されるクラスを設定できる。  (/src/App.vue)

```vue
<template>
	<div>
    	<router-link to="/" active-class="active" exact> HOME </router-link>
        <router-link to="/about" active-class="active"> ABOUT </router-link>
        <router-view></router-view>
    </div>
</template>

<style scoped>
.active{
    font-size: 30px;
}
</style>
```



## URLをJavaScriptから変更する($router.push)

`this.$router.push({path: '遷移先URL'})`とすることで、JavaScriptから遷移させることができる(/src/App.vue)

```vue
<template>
	<div>
        <button @click="toAbout">to About</button>
        <router-view></router-view>
    </div>
</template>

<script>
export default {
    methods: {
        toAbout() {
            this.$router.push({path: 'about'})
        }
    }
}
</script>
```



## 動的なURL（path: /xxx/:yyy, $route.params）

`path '/xxx/:yyy'`のように、コロンを使ってパラメータ(`yyy`)を指定することで、動的なURLができる

 (/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path:'/',  			 
            component:'Home'	
        },
        {
            path: '/about/:id', // パラメータidを指定
            component:'About'	
        }
    ]
})
```

$route.params.idで動的なURLのパラメータにアクセスできる (/src/views/About.vue)

```vue
<template>
	<div>
        <!--  -->
        <p>No. {{$route.params.id}}</p>
    </div>
</template>
```

※ 動的なURLはライフサイクルフックが呼ばれないので、URLの変更で何か処理をさせたい場合は、watchで$routeを監視する。



## 動的なURLのパラメータをpropsからアクセス (props: true)

`props: true`にすることで、動的パラメータをpropsでアクセスできる

 (/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path:'/',  			 
            component:'Home'	
        },
        {
            path: '/about/:id', 
            component:'About',
            props: true     	// propsを追加
        }
    ]
})
```

$route.params.idで動的なURLのパラメータにアクセスできる (/src/views/About.vue)

```vue
<template>
	<div>
        <p>ID: {{id}}</p>
    </div>
</template>

<script>
export default{
    props: ['id']
}
</script>
```

※ 動的なURLはライフサイクルフックが呼ばれないので、URLの変更で何か処理をさせたい場合は、watchで$routeを監視する。



## router-view のなかにrouter-view (children)

`children`を追加することでネストされたrouter-viewを実現できる (/src/router.js)

```js
import Vue from 'vue';
import Router from 'vue-router'
import Home from '/views/Home.vue' 
import About from '/views/About.vue'
import AboutChild from '/views/AboutChild.vue'

Vue.use(Router)

export default new Router({
    routes:[
        {
            path:'/',  			 
            component:'Home'	
        },
        {
            path: '/about', 
            component:'About',
            children:: [ // childrenオプションでpath, componentを設定する
            	{path: "child", component: AboutChild} // …/about/childでアクセス可
            ]
        }
    ]
})
```



## 名前付きのルートを使う (name)

`name`を使ってルートに名前を設定する (/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path: '/about:id', 
            component:'About',
            children:: [{
            	path: "child",
            	component: AboutChild,
            	name: 'name-child'  // ルートの名前を設定
        	}]
        }
    ]
})
```

`name`で指定したルートの名前を渡す。パラメータは`params`でオブジェクトで指定する (/src/views/App.js)

```vue
<template>
	<div>
        <router-link :to= "{name:'name-child', params:{id:1}}"> ABOUT </router-link>
        <router-view></router-view>
    </div>
</template>
```



## クエリにアクセス (query)

(/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path: '/about', 
            component:'About',
            name: 'about' // 名前付きルートを設定
        }
    ]
})
```

クリックすると/about?id=1というURLになる (/src/App.vue)

```vue
<template>
	<div>
		<!-- クリックすると /about?id=1&page=2というURLになる-->
        <router-link :to= "{name:'about', query:{id:1, page:2}}"> ABOUT </router-link>
        <!-- こちらでも可能 -->
        <router-link to="/about?id=1&page=2"></router-link>
        <router-view></router-view>
    </div>
</template>
```

クエリは`this.$route.query.id`で取得できる。



## リダイレクト機能 (redirect)

`redirect`を使うことで、リダイレクトを実装できる (/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path: '/about', 
            component:'About'
        },
        {
            path:'*',		// アスタリスクを指定することで任意のURLという意味になる
            redirect:'/'	// 遷移先のURLを指定
        }
    ]
})
```



## router-viewにトランジション (transition)

router-viewにもトランジションを適用させることができる (/src/App.vue)

```vue
<template>
	<div>
        <transitin name="fade" mode="out-in">
	    	<router-view></router-view>
    	</transitin>
	</div>
</template>

<style scoped>
.fade-enter,
.fade-leave-to {
    opacity: 0;
}
.fade-enter-active,
.fade-leave-active{
    transition: opacity .5s    
}
</style>
```

## # idを指定する (hash)

  クリックすると/about#nextというURLになる (/src/App.vue)

```vue
<template>
	<div>
		<!-- クリックすると /about#nextというURLになる-->
        <router-link :to= "{name:'about', hash: 'next'}"> ABOUT </router-link>
        <!-- こちらでも可能 -->
        <router-link to="/about#next"></router-link>
        <router-view></router-view>
    </div>
</template>
```



## 指定IDにスクロールさせる (scrollBehavior)

トランジションがない場合のみ使用できる。これは、transitionがあると、#nextが発生する前にscrollBehaviorが起動するためである (/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path:'/',  			 
            component:'Home'	
        }
    ],
    scrollBehavior(to, from, savedPosition) {
        // 前回の位置に戻る
        if(savedPosition) {
            return savedPosition
        }
        // URLにhashが含んでいたらハッシュの位置まで移動
        if(to.hash) {
            return {
                selector: to.hash
            }
        }
        // ページの先頭に移動
        return {x: 0, y: 0}
    }
})
```



## すべてのページの遷移時に実行する (beforeEach)

/src/main.js

```js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

// to:$route(次の遷移先の状態) from:$route(前の状態) next:次の遷移先に進む関数
router.beforeEach((to, from, next) => {
    console.log('before each!')
    // 引数も取れる
    // next(false):次に遷移させない
    // next('/'):'/'に遷移
    next()
})

new Vue({
    router,
    render: h => h(App)
}).$mount("#app")

```



## 特定のページの遷移時に実行する (beforeEnter)

`boforeEnter`を使う (/src/router.js 一部抜粋)

```js
export default new Router({
    routes:[
        {
            path: '/about', 
            component:'About',
            beforeEnter(to, from, next) {
                console.log('before enter!')
                // 引数も取れる
                // next(false):次に遷移させない
                // next('/'):'/'に遷移
                next()
            }
        },

    ]
})
```

## ナビゲーションガードをコンポーネントに指定

Vueコンポーネントに記載する

```vue
<script>
export default {
    beforeRouteEnter(to, from, next) {
        // コンポーネントを描画するルートが確立する前
        next()
    },
    beforeRouteUpdate(to, from, next) {
        //　コンポーネントを描画するルートが変更されたとき
    	next()
    },
    boforeRouteLeave(to, from, next) {
    	//  コンポーネント終了後（ナビゲーションから離れていく時）
        const isLeave = window.confirm("このページを離れますか？")
        if(isLeave) {
            next()
        }else {
	        next(false)        
        }
    }
}
</script>
```



## 遅延ローディング (const xx = () => import("./xxx.vue"))

router.jsのimport分の記載方法を変えることで遅延ローディング（後からjavascriptを取得する）が可能

（router.jsの一部を抜粋）

```js
// ● 今までの書き方
// import Home from './views/Home.vue' 

// ● 遅延ローディングの場合
const Home = () => import(/* webpackChunkName: "Home" */ "./views/Home.vue")

```


# 参考
https://router.vuejs.org/ja/installation.html