JavaScript
vue.js
webpack
Vuex
vue-router

Vue.jsとVuexとvue-routerとwebpackで単一ファイルコンポーネント化してTodoListを作ってみた

More than 1 year has passed since last update.

はじめに

前回の「Vue.jsとVuexとwebpackで単一ファイルコンポーネント化してTodoListを作ってみた」にvue-routerをいれて、Single Page Applicationにしてみたので書いていきます。

※タイトルがどんどん長くなる・・・

成果物

機能は前回と同じく「追加」と、「完了」と、「完了から戻す」3つだけ。

Vue.jsとVuexとwebpackと単一ファイルコンポーネントの簡単な説明は前回のQiitaに書いたので割愛。

スペック

  • vue-routerは少しだけ使ったことある
  • SPAっぽいものを実装した経験がある

vue-router

公式

Vue.jsでSPAを作る際のライブラリ。

router-link

vue-routerでリンクを作成するコンポーネント。

aタグのようなもの

<router-link to="/foo">Go to Foo</router-link>

router-view

SPAで書き換わる中身のコンポーネント。

下記例ではfooやbarに遷移するとrouter-viewは書き換わるがh1とかは書き替わらない。

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <router-view></router-view>
</div>

ソースコード解説

全体

package.json


{
  "name": "vuex-webpack-components-vue-router-todo-sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack",
    "dev-watch": "webpack --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vue": "^2.4.2",
    "vue-router": "^2.7.0",
    "vuex": "^2.4.0"
  },
  "devDependencies": {
    "css-loader": "^0.28.7",
    "vue-loader": "^13.0.4",
    "vue-template-compiler": "^2.4.2",
    "webpack": "^3.5.6"
  }
}

前回から追加したものはvue-routerscriptsdev-watchを追加しました。

今まではビルドの度に毎回webpackを動かしていましたが、watchオプションをつけ自動でビルドさせています。

webpack.config.js

前回と差分なし

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Vuex Vue-Router Components Todo Sample</title>
  <link rel="stylesheet" href="">
  <style>
    main {
      display: flex;
    }
  </style>
</head>
<body>
  <div id="app">
    <header>
      <router-link to="todoInput">Go to TodoInput</router-link>
      <router-link to="todoList">Go to todoList</router-link>
      <router-link to="doneList">Go to doneList</router-link>
    </header>
    <router-view></router-view>
  </div>
  <script src="js/bundle.js"></script>
</body>
</html>

router-linkコンポーネントを利用し、3つのリンクを作成。

また、router-viewコンポーネントを記述しています。

app.js

import Vue from 'vue';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import routes from './router/routes.js';
import actions from './action/actions.js';
import mutations from './mutation/mutations.js';
Vue.use(Vuex);
Vue.use(VueRouter);

var store = new Vuex.Store({
  state: {
    todos: [],
    dones: []
  },
  getters: {
    todos(state) {
      return state.todos;
    },
    dones(state) {
      return state.dones;
    }
  },
  actions: actions,
  mutations: mutations,
});

const router = new VueRouter({
  routes
});

new Vue({
  el: '#app',
  store: store,
  router: router,
});

すっきりとしたJSに!

actionsとmutationsはそのまま別JSファイルに出しました。

※stateとgettersも出したほうが良い気がしたが今回はそのまま

VueRouterの引数にroutesを渡して生成し、Vueに渡してvue-routerの設定は終わり。

routes.js

import indexView from './../view/indexView.vue';
import todoInputView from './../view/todoInputView.vue';
import todoListView from './../view/todoListView.vue';
import doneListView from './../view/doneListView.vue';

export default [
  { path: '/', component: indexView },
  { path: '/todoInput', component: todoInputView },
  { path: '/todoList', component: todoListView },
  { path: '/doneList', component: doneListView },
];

今回のメインのvue-routerのルーティング設定ファイル。

vue-routerの公式は一つのJSに書かれていますが、今回は別ファイルにしました。

各URLとコンポーネントを紐付けています。

/todoInputにアクセスすると、router-viewtodoInputView.vueが表示されます。

todoInputView.vue

<template>
  <section class="wrap">
    <h2>Todo Input</h2>
    <todo-input></todo-input>
  </section>
</template>

<style scoped>
  .wrap {
    padding: 0 10px;
  }
</style>

<script>
  import todoInput from './../components/todoInput.vue';
  export default {
    components: {
      todoInput
    },
  }
</script>

単一ファイルコンポーネント。

todoInput.vueをimportし<template>内で表示しています。

todoInput.vue

<template>
  <input type="text" @keyup.enter="addTodoText"/>
</template>

<script>
  export default {
    methods: {
      addTodoText(e) {
        var text = e.target.value;
        this.$store.dispatch('addTodo', {
          text: text
        });
        e.target.value = '';
      }
    }
  }
</script>

input要素と挙動だけ書かれた単一ファイルコンポーネント。

所感

vue-roterの導入自体は難しくなくすんなりできた。