やりたいこと
Reactに疲れて去年から最近流行りのVue.jsに手を出してみた。最終的には以下の構成でWebアプリを作りたい。
- スクリプト: Typescript
- マークアップ: pug
- スタイル: stylus
- UIフレームワーク: Element (http://element.eleme.io/)
- ルーティング: vue-router (https://router.vuejs.org/)
- 状態管理: vuex (https://vuex.vuejs.org/)
- ビルド: Webpack
- エディタ: VSCode
今回はまずは
- スクリプト: ES6
- マークアップ: html
- スタイル: css3
- ルーティング: vue-router (https://router.vuejs.org/)
- ビルド: Webpack
- エディタ: VSCode
でトップページとシンプルなTodo管理画面の2つを作ってみる。
成果物 -> https://github.com/lucidfrontier45/vue-todo-test/tree/0.1.1
準備
環境
- Ubuntu 16.04
- node v8.1.2
インストール
vue-cliを使用するとcreate-react-app並に簡単に始められる。
$ npm i -g yarn veu-cli
$ vue-init webpack vue-todo
vue-initはいろいろ聞いてくるが基本的には全部yesで答えておけばOK。これでプロジェクトが作成されるので依存ライブラリをインストールし、webpackのdev-serverも簡単に立ち上げられる。
$ cd vue-todo
$ yarn install
$ yarn run dev
ちなみに自分は勝手にブラウザを立ち上げられるのが嫌なのでconfig/index.js
のdev.autoOpenBrowser
をfalse
にしている。
TodoApp実装
プロジェクトはcreate-react-appとほぼ同じでindex.html
のroot divにアプリがすべてレンダリングされる仕組みだ。
Vueの特徴としてはいろいろなスタイルの書き方があり、中でもSingle File Compinent(SFC)という.vue
ファイルにhtml/css/jsすべてを書けるというのが一番おもしろい。HTMLもstyle,scriptでcssやjsをかけるが、それをパーツごとに分解できるというイメージだ。
以下のファイルがTodoAppの本体部分。
<template>
<div>
<div>
<input type="text"
v-model="input"></input>
<button @click="handleAdd">Add</button>
<select v-model="mode">
<option label="All"
value="all"></option>
<option label="Completed"
value="completed"></option>
<option label="Incomplete"
value="incomplete"></option>
</select>
</div>
<ul>
<li v-for="todo in filteredTodos"
:key="todo.id">
<button @click="() => handleToggle(todo.id)">
<span v-if="todo.completed">
restore
</span>
<span v-else>
done
</span>
</button>
{{todo.msg}}
</li>
</ul>
</div>
</template>
<script>
import { addTodo, todos, toggleTodo } from "../todos"
function filterTodos(todos, mode) {
if (mode === "all") {
return todos
} else if (mode === "completed") {
return todos.filter(todo => todo.completed)
} else {
return todos.filter(todo => !todo.completed)
}
}
export default {
data: function() {
return {
input: "",
mode: "incomplete",
todos
}
},
methods: {
handleAdd: function() {
const v = this.input.trim()
if (v.length > 0) {
addTodo(v)
this.input = ""
}
},
handleToggle: function(idx) {
toggleTodo(idx)
}
},
computed: {
filteredTodos: function() {
return filterTodos(this.todos, this.mode)
}
}
}
</script>
<style scoped>
ul {
margin-left: 0;
padding-left: 0;
transform: translateX(50%);
text-align: left;
list-style-position: inside;
}
</style>
<template>
タグでhtml、<script>
タグでjs、 <style>
タグ中にcssを書ける。
要点
- jsではdata, methods, computedを含んだオブジェクトを作る。dataはreactでいうstateに相当し、methodsは
@click
などで使用するものをここに書く。computedはdataに対する何らかの変換を施し、最終的に表示する変数の内容を作る。computedはdataが変わると自動的に再計算される。 - htmlのテキスト部分には
{{varname}}
、divなどの中の属性の時はv-bind:attr=varname
か:attr=varname
のようにして変数を使用できる。ここでの表現にはdata, methods, computedなどで定義したものが使用できる。 - template中の
@click
はv-on:click
の略で、ボタンなどをクリックした時の挙動を設定できる。指定は関数やアロー演算子を使用した書き方などがある。 -
v-model="input"
は双方向バインドと呼ばれるもので、画面の表示とcomponentのdataの中身を同期できる仕組みである。 -
v-for
,v-if
などのテンプレートエンジンでお馴染みの機能もある。 - 詳しくは https://jp.vuejs.org/v2/guide/ を参照のこと
小並感
- Reactを知っている人にとっては公式ガイドを一度読んでおけば基本的にはそんなに困ることはなさそう。
- それでいてJSXを強要されないのでマークアップ、スタイリングはデザイナーにお願いし、エンジニアはscriptの機能、動作部分に集中できそう。
- vue-cliのおかげで導入の敷居がものすごく低い。
次回はpug,stylusそしてElementを導入する。