2016/10/10

Vue.js2.0とvue-routerでナビゲーションバーをつくる

ブログの中の人」のページを新しくするために、Vue.jsとvue-routerを使ってWebサイトを作っていた。ちょっとだけ引っかかったところがあったので、共有も含めてナビゲーションバーの作り方を説明する。

今回は、最小構成でつくる場合と、vue-cli(vue-loader)を使ってつくる場合を紹介する。


使っているバージョンは以下のとおり。
  • Vue.js - 2.0.1
  • vue-router - 2.0.0


最小構成でナビゲーションバーをつくる


<div id="app">
  <nav>
    <ul>
      <router-link tag="li" to="/" exact><a>home</a></router-link>
      <router-link tag="li" to="/foo"><a>foo</a></router-link>
      <router-link tag="li" to="/bar"><a>bar</a></router-link>
    </ul>
  </nav>

  <router-view></router-view>
 </div>
// Components
const Home = { template: '<div>home</div>'    }
const Foo  = { template: '<div>foo</div>' };
const Bar  = { template: '<div>bar</div>' };

// Router
const routes = [
    { path: '/',    component: Home },
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar }
];

const router = new VueRouter({
    routes
});

const app = new Vue({
    router
}).$mount('#app');

まずindex.htmlから説明する。
4~6行目の router-link で指定した部分がナビゲーションバーのボタンに相当する。
デフォルトだと router-link はaタグに変換されるため、tag="li" を指定してliタグになるようにしている。(結局は、中でaタグなどのクリッカブルな要素が必要だけど)

to="/" to="/foo" の部分がルーティングの肝となる。クリックしたときにURLがtoで指定されたパスになる。
もしルートパスが"/"ではなく、"domain.com/app/"になる場合は、new VueRouterのコンストラクタのオプションに"base: '/app/'" のように指定する。

そして現在のパスによって、自動的に.router-link-activeというクラスが設定される。
このクラスにスタイルを適用させれば、現在選択されているボタンに効果をつけることができる。

4行目だけexactという属性が入っているが、これがないと"/foo"にアクセスしたときに、to="/"とto="/foo"の両方に.router-link-activeクラスが設定されてしまうからだ


index.jsについては、とくに説明するところはないかなぁ。




vue-cli(vue-loader)を使ってナビゲーションバーをつくる


まずは、ディレクトリ構成から。
.
├─ App.vue    // <-- これがメインのページ
├─ main.js    // <-- Vue.jsやvue-routerを読み込んでインスタンス化する
├─ routes.js    // <-- ルーティングの定義をする
├─components
│   ├── CompHoge.vue
│   └── CompFuga.vue
└─pages
    ├── Home.vue    // <-- "/" のときに表示するページ
    └── Products.vue    // <-- "/products" のときに表示するページ

import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import routes from './routes'

Vue.use(VueRouter)

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

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
export default [
  {
    path: '/',
    component: require('./pages/Home')
  },
  {
    path: '/products',
    component: require('./pages/Products')
  }
]
<template>
<div id="app">
    <ul>
        <li><router-link to="/" exact>Home</router-link></li>
        <li><router-link to="/products">Products</router-link></li>
    </ul>
    <router-view :data="myData"></router-view>
</template>

<script>
import CompHoge from './components/CompHoge'
import myData from '../static/data.json'

export default {
  components: {
    CompHoge 
  },
  data () {
    return {
      myData: myData
    }
  }
}
</script>
<template>
  <span>{{data}}</span>
  <comp-hoge :data="data"><comp-hoge>
</template>

<script>
import CompHoge from '../components/CompHoge'
export default {
  components: {
    CompHoge
  },
  props: ['data']
}
</script>
<template>
  <span>{{data}}</span>
  <comp-fuga :data="data"><comp-fuga>
</template>

<script>
import CompFuga from '../components/CompFuga'
export default {
  components: {
    CompFuga
  },
  props: ['data']
}
</script>

わかりにくいかもしれないが、メインにApp.vueがあり、パスによってpages/Home.vuepages/Products.vueを読み込んで表示するか制御する。

router-viewの部分に表示されるのだが、そのときに子コンポーネント(ここではHome.vueやProducts.vue)にデータを渡したい場合は、v-bindを使う。
詳しくは次の記事を参考にしてほしい。
または「ブログの中の人」のリポジトリを参考にしてほしい。


参考サイト



以上


written by @bc_rikko

0 件のコメント :

コメントを投稿