vue.js
vue-router

Vue.jsでSPAサイトを作成するチュートリアル【2. ルーター編】

Vue.jsを使い始めていろいろできることが多くなってきたので、整理する意味も兼ねてチュートリアルにまとめます。
今回はコーポレートサイトを想定して作成していきます。
※記事が長くなったのでチュートリアルを分割しました。

目次

前提

  • タスクはnpm scriptsで一限管理
  • コマンドはyarnを使用
  • vue-cliwebpack-simpleを使用

バージョン

  • "vue": "^2.5.11"
  • "vue-router": "^3.0.1"
  • "webpack": "^3.6.0"

SPAサイトの全体像

今回作成するSPAサイトの全体像は以下です。

  • index
  • about
  • service
  • recruite
  • contact

ディレクトリ構成は以下です。
/pagesに各ページのディレクトリを作成し、templateとstyleとscriptを各外部ファイルとして扱います。

/src
  /layouts
    Default.vue
  /pages
    /Index
      Index.vue
      Index.pug
      Index.scss
      Index.js
    /About
      About.vue
      About.pug
      About.scss
      About.js
    /Service
      Service.vue
      Service.pug
      Service.scss
      Service.js
    /Recruite
      Recruite.vue
      Recruite.pug
      Recruite.scss
      Recruite.js
    /Contact
      Contact.vue
      Contact.pug
      Contact.scss
      Contact.js
  App.vue
  main.js
  router.js
  index.html
  // 以下省略

ルーターを実装する前に動作確認用としてindexとaboutを先に作成しておきましょう。

HTMLは今回はpugを使用します。
pugを追加します。

$ yarn add -D pug

indexページを作成します。

/src/pages/Index/Index.vue
<template
  lang="pug"
  src="./Index.pug"
/>

<script src="./Index.js" />

<style
  lang="scss"
  src="./Index.scss"
  scoped
/>


/src/pages/Index/Index.pug
main.main
  p {{ text }}
  .block
    | block

/src/pages/Index/Index.js
export default {
  data: function () {
    return {
      text: 'index'
    }
  }
}

/src/pages/Index/Index.scss
.block {
  color: #f00;
  display: flex;
}

同様にaboutページもvue, pug, js, scssの各ファイルを作成しましょう。
vueファイルのtemplateはpugで統一したいので、App.vueのtemplateもpugで書き直しておきましょう。

App.vue
<template lang="pug">
#app.app
  img(src="./img/logo.png")
</template>

vue-routerの環境構築

vue-routerを追加します。

$ yarn add vue-router

ルーターファイルを追加し記述します。
/layouts/Default.vueのコンポーネントの子として各ページをchildren内に記述します。

/src/router.js
export default [
  {
    path: '/',
    name: 'index',
    component: require('./layouts/Default.vue').default,
    children: [
      {
        path: '',
        name: 'index',
        component: require('./pages/Index/Index.vue').default,
      },
      {
        path: '/about/',
        name: 'about'
        component: require('./pages/About/About.vue').default
      }
      // 省略
    ]
  }
]

参考:ネストされたルート

main.jsを以下に差し替えます。

main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import Routes from './router.js'

Vue.use(VueRouter)

const router = new VueRouter({
  mode: 'history',
  routes: Routes
})

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

App.vueを以下に書き換えます。

/src/App.vue
<template lang="pug">
#app.app
  router-view
</template>

共通レイアウトを作成します。

$ touch src/layouts/Default.vue

Default.vueに記述します。

/src/layouts/Default.vue
<template lang="pug">
.wrap
  p header
  router-link(to="/") index
  router-link(to="/about/") about
  router-link(to="/service/") service
  router-link(to="/recruite/") recruite
  router-link(to="/contact/") contact
  main#main.main router-view
  p footer
</template>

ローカルで作業する際にbrouser-syncの以下の設定をしておくと、各URLに直接アクセスできるようになります。

参考:react-routerとbrowser-syncを利用して快適に開発するちょっとした設定

ブラウザで確認してページ遷移してindexページとaboutページがそれぞれ表示されれば成功です。
その他各ページも同様に作成していきましょう。
その際に、router.jsに各ページの指定も忘れないように追記しましょう。
遷移するか確認するためにDefault.vueのrouter-linkを追記すると良いでしょう。

ページ遷移時の表示位置を最適化

ページ遷移した時に中途半端な位置で表示することがあります。
他のページへ遷移した場合はページトップ、ブラウザの「戻る」「進む」ボタンを押すと遷移前の位置を表示するよう最適化します。

main.js
// 省略
const router = new VueRouter({
  mode: 'history',
  routes: Routes,
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { x: 0, y: 0 }
    }
  }
})
// 省略

参考:スクロールの振る舞い

まとめ

ルーターはSPAでは重要な役割を果たしていて、ページ間のやりとりに重宝します。
最近のウェブサイトはページの非同期遷移をおこなっているものが増えてきました。
積極的に取り入れてユーザー体験を向上させましょう。