【jQuery】クライアントMVCフレームワーク - Tiny【JavaScript】

#はじめに
以前作ったものを少し修正したものを作成しました。
導入は、jqueryを読み込んだ後に本ライブラリを読み込むだけです。

ファイルサイズが小さく機能も少なめなので名前は**Tiny**です。

jQueryが少しわかっていれば使えます。
2,3分もあれば使い方が分かるんじゃないでしょうか？
しかも、勝手にクライアントサイドがMVCになります。

# TODOを作ってみる
ではTODOをプログラムしてみようと思います。

**TODOの仕様**ですが
・addボタンでテキスト内容をTODOに追加
・delete allボタンでTODOを全てクリア
といたってシンプルなものです。

# TODOをjQueryのみで作ってみる
ではTODOを**jQueryのみ**でMVCで実装しようと思います。


```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>tiny framework test</title>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/onlyjquery.js"></script>
</head>
<body>
<h3>TODO only jQuery</h3>
<input id="todo_text" type="text"><br>
<input id="add_button" type="button" value="add">&nbsp;
<input id="delete_all_button" type="button" value="delete all"><br>
<br>
<table id="todo_table">
	<thead><tr><th>todo</th></tr></thead>
	<tbody></tbody>
</table>
</body>
</html>
```

```js:onlyjquery.js
$(function() {
	// モデル
	var todos = [];
	
	// addボタンクリック時の処理
	$('#add_button').click(function(e) {
		todos.push($('#todo_text').val());	// モデルを更新
		updateView();	// ビューを更新
	});

	// delete allボタンクリック時の処理
	$('#delete_all_button').click(function(e) {
		todos = [];	// モデルを更新
		updateView();	// ビューを更新
	});

	// ビューを更新
	function updateView() {
		var strHtml = '';
		todos.forEach(function(todo) {
			strHtml += '<tr><td>' + todo + '</td></tr>';
		});
		$('#todo_table tbody').html(strHtml);
	}
});
```

jQueryのみのプログラムを少し説明します。

var todoはモデルです。
イベントハンドラがコントローラで
イベントハンドラで、モデルの更新を行い、モデルの情報のみでビュー(画面)を更新します。

# TODOをTinyで作ってみる
次に**自作フレームワークTiny**を使ってTODOを実装しようと思います。

```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>tiny framework test</title>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/jquery.tiny.min.js"></script>
<script src="js/withtiny.js"></script>
</head>
<body>
<h3>TODO with Tiny</h3>
<input id="todo_text" type="text"><br>
<input id="add_button" type="button" value="add">&nbsp;
<input id="delete_all_button" type="button" value="delete all"><br>
<br>
<table id="todo_table">
	<thead><tr><th>todo</th></tr></thead>
	<tbody></tbody>
</table>
</body>
</html>
```

```js:withtiny.js
$(function() {
	$.Tiny({
		// モデル(変数)
		variable: {
			todos: []
		},
		// イベントハンドラ
		controller: [
			{// addボタンクリック時の処理
				target: '#add_button',
				event: 'click',
				name: 'add'
			},

			{// delete allボタンクリック時の処理
				target: '#delete_all_button',
				event: 'click',
				name: 'delete_all'
			},
		],
		// モデル変更
		model: {
			init: function(variable) {

			},
			add: function(variable, e, src) {
				variable.todos.push($('#todo_text').val());
			},
			delete_all: function(variable, e, src) {
				variable.todos = [];
			},
		},
		// ビュー更新
		view: {
			init: function(variable) {

			},
			add: function(variable, e, src) {
				this.update(variable, e, src);
			},
			delete_all: function(variable, e, src) {
				this.update(variable, e, src);
			},
			update :function(variable, e, src) {
				var strHtml = '';
				variable.todos.forEach(function(todo) {
					strHtml += '<tr><td>' + todo + '</td></tr>';
				});
				$('#todo_table tbody').html(strHtml);
			}
		}
	});

});
```

# Tinyの説明
さあ、やっとTinyの説明ができます。

**$.Tiny()の引数**は

- **variables**：モデルの定義
- **controller**:イベントハンドラ
- **model**:モデル変更処理
- **view**: ビューの変更処理(モデルのみを参照してビューを更新すること)


をプロパティとするオブジェクトです。では、プロパティ毎に細かく説明します。

# variables

モデルを定義します。オブジェクト又は配列である必要があります。
(モデルなので、modelとしようと思いましたがモデルの変更をmodelとしたかったため、variablesにしてしまいました)

# controller
イベントハンドラを定義します。
jQueryのonメソッドで
delegateしないパターンとするパターンがありますが

**delegateしないパターン**
例：$('#add_button').on('click', function() {});

```js
contorller: [
    {
        target: '#add_button',
        event: 'click',
        name: 'add'
    },
    ...
}
```


**delegateするパターン**
例：$('body').on('click', 'div', function() {});

```js
contorller: [
    {
        delegator: 'body',
        target: '#div',
        event: 'click',
        name: 'add'
    }
    ...
]
```

このようにdelegatorが必要な場合は指定してください。
またnameプロパティは必須です。このnameで、モデル変更、ビュー変更を行いますので、
わかりやすい名前を付けたほうが良いと思われます。

# model
モデルの変更を行います
contorllerで

```js
contorller: [
    {
        target: '#add_button',
        event: 'click',
        name: 'add'
    },
    ...
]
```

とした場合、modelは次のように書きましょう。

```js
model: {
	add: function(variable, e, src) {
        // ここでモデル(variable)を変更する
	},
    ...
}
```

controllerで指定したnameと同じ名前のプロパティを用意しましょう。
variableがモデルですので、ここで変更しましょう。
非同期のプログラムにも対応しています。非同期処理はPromiseで書きましょう。

# view
ビュー(画面)の変更を行います。

contorllerで

```js
contorller: [
    {
        target: '#add_button',
        event: 'click',
        name: 'add'
    },
    ...
]
```

とした場合、viewは次のように書きましょう。

```js
view: {
	add: function(variable, e, src) {
        // ここでモデル(variable)を変更する
	},
    ...
}
```

controllerで指定したnameと同じ名前のプロパティを用意しましょう。
引数のvariableを参照して画面を変更しましょう。
上の例なら、#add_buttonがクリックされる→モデルの変更(model.add)→ビューの変更(view.add)
といった具合にプログラムが動きます。

# テクニック

サンプルのview.updateのようにメソッドを使いまわすことも可能です。(privateのように使えます。)

# Tinyのダウンロード

自由に使ってください。
[リンク](https://github.com/pgman/tiny)


# 【最後に】
MVCを利用すると、簡単に言えばプログラムの見通しが良くなります。
variablesだけ見れば、この画面はどのような変数をつっているのか一目瞭然ですし、
ビューがモデルと独立しているので、プログラムの改修も楽なはずです。