素のJavaScriptはとにかくコード量が多くなって面倒。
AngularJSは学習コストが高く、AngularJS2.0になると別モノになってしまう。
とにかく手軽にアプリが作れるフレームワークを、と探したところにMVVMフレームワークの「Vue.js」を見つけた。
ググるとなにかと「お手軽」というキーワードが目についたので、実際に使ってみた。
できあがったモノは、以下のサイトで触れる。
ToDoアプリ自体は、以下の2つのエントリとほとんど同じ。
準備
bower、tsd、NuGet、GitHubなどから以下のjsファイルと型定義ファイルをダウンロードする。
- vue
- vue.d.ts
View(HTML)
<!-- index.html -->
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Vue.js + TypeScript</title>
<style>
.done-true{
color: gray;
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="todoapp">
<h1>Vue.js + TypeScript</h1>
<p>Finished Task: {{getDoneCount}} / {{tasks.length}}</p>
<button v-on="click: deleteDone">Delete Finished</button>
<ul>
<li v-repeat="task: tasks">
<input type="checkbox" v-model="task.done" />
<span class="done-{{task.done}}">{{$index}}:{{task.body}}</span>
<a href="#" v-on="click: deleteTask($index)">[x]</a>
</li>
</ul>
<form onsubmit="return false;" v-on="submit: addNew">
<input type="text" v-model="newTaskBody" />
<input type="submit" value="add" />
</form>
</div>
<script src="./bundle.js"></script>
</body>
</html>
見た目、AngularJSとほとんど変わらない。
「ng-hoge」が「v-hoge」に変わり、「ng-click」が「v-on="click hoge"」に変わっただけ。
ウチの環境では、webpackを使ってjsファイルをバンドル化しているので、scriptの読み込みが1行になっている。
実装したjsファイルとライブラリは分けたほうが良いと思うんだけど、どうなんだろう?
ViewModel (TypeScript)
ViewModelとは、Viewを描画するための状態の保持と、Viewから受け取った入力を適切なカタチに変換してModelに伝達する役割。
だけど、ToDoアプリ自体小さなプログラムなので今回はModel層はなし。
// app.ts
/// <reference path="./typings/vue/vue.d.ts" />
import Vue = require('vue');
interface ITask {
body: string
done: boolean
}
class TodoApp extends Vue{
// タスク一覧
tasks: ITask[];
// 新規タスク
newTaskBody = '';
constructor() {
// to defer compilation in Vue
super(false);
this._init({
el: '#todoapp',
data: {
tasks: this.tasks,
newTaskBody: this.newTaskBody
},
computed: {
getDoneCount: this.getDoneCount
},
created: () => {
this.tasks = [
{ body: 'do this 1', done: false },
{ body: 'do this 2', done: false },
{ body: 'do this 3', done: false },
{ body: 'do this 4', done: false }
];
},
methods: {
addNew: this.addNew,
deleteTask: this.deleteTask,
deleteDone: this.deleteDone
}
});
}
/**
* タスクの追加
*/
addNew(): void{
var task = this.newTaskBody && this.newTaskBody.trim();
if (!task) {
return;
}
this.tasks.push({ body: task, done: false });
this.newTaskBody = '';
}
/**
* タスクの削除
* @param index :削除する行番号
*/
deleteTask(delIndex: number): void{
this.tasks.splice(delIndex, 1);
}
/**
* 済タスクの一括削除
*/
deleteDone(): void{
var oldTasks = this.tasks;
this.tasks = [];
oldTasks.forEach(task => {
if (!task.done) this.tasks.push(task);
});
}
/**
* 完了済み件数の取得
* @return 完了済み件数
*/
getDoneCount(): number{
var count = 0;
this.tasks.forEach(task => {
count += task.done ? 1 : 0;
});
return count;
}
}
export var todoApp = new TodoApp();
1行目:型定義ファイル(vue.d.ts)の読み込み
3行目:前述の通り、Webpackを使っているので
import Vue = require(‘vue’)
なんてことをしている。5行目:ひとつのタスクを表すinterface。それぞれのタスクに何かする機能を付けたいならclassにした方が良い。
10行目~87行目:ViewModelの実装
10行目:いろいろ実装するために、Vueを継承する。
12~14行目:ViewModelで保持するデータ(タスク一覧と新規タスク名)
18行目:Vueのコンストラクタにfalseを渡すと、コンパイルを遅延させられる。
20行目:見覚えのあるVueの定義は、this._initをオーバーライドするカタチで行う。
el
:対象となるHTML要素(Element)data
:バインドする値computed
:dataの値を利用した計算式のようなモノcreated
:初期化処理などに使うmethods
:イベントなどから呼び出す各種処理
48~88行目:computedやmethodsにバインドするメソッドの実装
91行目:最後にTodoAppクラスをインスタンス化してexportして終わり。インスタンス化だけでexportをしないと動かないので注意
※ 追記:2015/06/25 20:30
91行目:webpackを使わない場合は、export をすると「exports is not defined」というエラーが発生する。exportなしで「var todoApp = new TodoApp();」と書いたら動いた。
さいごに
今回作成したToDoアプリをGitHubにあげた。
AngularJSと比較すると、$scopeとかよくわからないモノがない分、理解しやすかった。
慣れもあるのかもしれないが、直感的で書きやすい印象だった。
Componentを使った実装や、Modelの存在をないものとして扱ってきたが、今後機会があったらまたブログにまとめようと思う。
とにかく手軽にWebアプリケーションがつくりたい!というなら、Vue.jsは良い選択肢になると思う。
参考サイト
以上
written by @bc_rikko
0 件のコメント :
コメントを投稿