Skip to content

Instantly share code, notes, and snippets.

@masahirompp
Created February 21, 2015 12:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masahirompp/0fc24cd168651bdcc2f4 to your computer and use it in GitHub Desktop.
Save masahirompp/0fc24cd168651bdcc2f4 to your computer and use it in GitHub Desktop.
javascript mvc (no framework) http://jsfiddle.net/54sjqL6z/
(function(todo) {
'use strict';
// viewの追加イベントを監視。TodoListに新規Todoを追加する。
todo.View.on('add', function(description) {
todo.TodoList.add(new todo.Todo(todo.TodoList.length, description));
todo.View.clearInput();
});
// viewの変更イベントを監視。モデルの状態を更新を命令。
todo.View.on('change', function(index) {
todo.TodoList[index].done();
});
})(this.todo);
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Todo MVC Sample</title>
<style>
.completed {
text-decoration:line-through;
}
</style>
</head>
<body>
<div>
<input type="text" id="todoInput">
</div>
<div>
<ul id="todoList"></ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"></script>
<script src="./util.js"></script>
<script src="./model.js"></script>
<script src="./view.js"></script>
<script src="./controller.js"></script>
</body>
</html>
(function(_, util, exports) {
'use strict';
// Model
var Todo = _.extend(function(id, description) {
this.id = id;
this.description = description;
this.complete = false;
}, util.events());
Todo.prototype.done = function() {
this.complete = true;
Todo.trigger('change', this);
};
// Collection
var TodoList = _.extend([], util.events());
TodoList.add = function(todo) {
this.push(todo);
this.trigger('change', TodoList);
};
// export
exports.Todo = Todo;
exports.TodoList = TodoList;
})(this._, this.util, this.todo = this.todo || {});
(function(_, exports) {
'use strict';
exports.events = function() {
var events = {};
return {
on: function(name, func) {
(events[name] || (events[name] = []))
.push(func);
return this;
},
trigger: function(name /*, ...args */ ) {
var funcs = events[name] || [];
var args = _.rest(arguments);
funcs.forEach(function(func) {
setTimeout(function() {
func.apply(null, args);
}, 0);
});
return this;
}
};
};
})(this._, this.util = this.util || {});
(function(_, util, exports) {
'use strict';
// モデルの参照
var Todo = exports.Todo;
var TodoList = exports.TodoList;
// DOM参照
var input = window.document.getElementById('todoInput');
var ul = window.document.getElementById('todoList');
var View = _.extend({}, util.events());
var todoHtml = _.template('<li id="todo_<%= id %>" <% if(complete) { %>class="completed" <% }%>><%= description %></li>');
// DOM操作 TodoListを描画
function render(todoList) {
ul.innerHTML = todoList.reduce(function(html, todo) {
return html + todoHtml(todo);
}, '');
}
// DOM操作 Todoの状態を更新
function complete(todo) {
var target = window.document.getElementById('todo_' + todo.id);
target.className = todo.complete ? 'completed' : '';
}
// DOM操作 入力をクリア
function clearInput() {
input.value = '';
}
View.clearInput = clearInput; // export
// モデルを監視
Todo.on('change', complete);
TodoList.on('change', render);
// Event通知
input.addEventListener('keydown', function(e) {
if (e.keyCode === 13 && e.target.value) View.trigger('add', e.target.value); // inputでENTERが押下された場合に通知
});
ul.addEventListener('click', function(e) {
if (e.target.tagName.toLowerCase() === 'li') {
View.trigger('change', _.last(e.target.id.split('_'))); // 各アイテムがクリックされた時に通知
}
});
// export
exports.View = View;
})(this._, this.util, this.todo);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment