<!doctype html>
<html>
head>
title>Javascript MVC</script src="https://code.jquery.com/jquery-2.2.3.min.js" ></script>
style>
bodydiv class="js-container">
input type="text" class="js-task-textbox">
="button"="js-add-task-button" value="Add Task"="js-tasks-container"div<!-- end tasks -->
="js-complete-task-button"="Complete Tasks"="js-delete-task-button"="Delete Tasks" end js-container -->
="EventDispatcher.js"="TaskModel.js"="TaskView.js"="TaskController.js"="App.js">
var Event = function (sender) {
this._sender = sender;
this._listeners = [];
}
Event.prototype = {
attach: (listener) {
this._listeners.push(listener);
},notify: (args) {
for (var i = 0; i < this._listeners.length; i += 1) {
this._listeners[i](._sender,args);
}
}
};
var TaskModel = () {
this.tasks = [];
this.selectedTasks =this.addTaskEvent = new Event();
this.setTasksAsCompletedEvent = this.deleteTasksEvent = );
};
TaskModel.prototype = {
addTask: (task) {
.tasks.push({
taskName: task,taskStatus: 'uncompleted'
});
.addTaskEvent.notify();
},getTasks: () {
return .tasks;
},setSelectedTask: (taskIndex) {
.selectedTasks.push(taskIndex);
},unselectTask: this.selectedTasks.splice(taskIndex,1);
},setTasksAsCompleted: var selectedTasks = .selectedTasks;
var index in selectedTasks) {
this.tasks[selectedTasks[index]].taskStatus = 'completed';
}
.setTasksAsCompletedEvent.notify();
[];
},deleteTasks: .selectedTasks.sort();
var i = selectedTasks.length - 1; i >= 0; i--) {
this.tasks.splice(this.selectedTasks[i],1)">);
}
// clear the selected tasks
[];
.deleteTasksEvent.notify();
}
};
var TaskView = (model) {
this.model = model;
);
this.selectTaskEvent = this.unselectTaskEvent = this.completeTaskEvent = this.deleteTaskEvent = );
.init();
};
TaskView.prototype = {
init: () {
.createChildren()
.setupHandlers()
.enable();
},createChildren: cache the document object
this.$container = $('.js-container');
this.$addTaskButton = this.$container.find('.js-add-task-button'this.$taskTextBox = this.$container.find('.js-task-textbox'this.$tasksContainer = this.$container.find('.js-tasks-container');
;
},setupHandlers: () {
this.addTaskButtonHandler = this.addTaskButton.bind(this.selectOrUnselectTaskHandler = this.selectOrUnselectTask.bind(this.completeTaskButtonHandler = this.completeTaskButton.bind(this.deleteTaskButtonHandler = this.deleteTaskButton.bind(/**
Handlers from Event Dispatcher
*/
this.addTaskHandler = this.addTask.bind(this.clearTaskTextBoxHandler = this.clearTaskTextBox.bind(this.setTasksAsCompletedHandler = this.setTasksAsCompleted.bind(this.deleteTasksHandler = this.deleteTasks.bind(this.$addTaskButton.click(.addTaskButtonHandler);
this.$container.on('click','.js-task',.selectOrUnselectTaskHandler);
.completeTaskButtonHandler);
.deleteTaskButtonHandler);
*
* Event Dispatcher
this.model.addTaskEvent.attach(.addTaskHandler);
.clearTaskTextBoxHandler);
this.model.setTasksAsCompletedEvent.attach(.setTasksAsCompletedHandler);
this.model.deleteTasksEvent.attach(.deleteTasksHandler);
.addTaskEvent.notify({
task: .$taskTextBox.val()
});
},completeTaskButton: .completeTaskEvent.notify();
},deleteTaskButton: .deleteTaskEvent.notify();
},selectOrUnselectTask: (event) {
var taskIndex = $(event.target).attr("data-index"if ($(event.target).attr('data-task-selected') == 'false') {
$(event.target).attr('data-task-selected',1)">true);
.selectTaskEvent.notify({
taskIndex: taskIndex
});
} else {
$(event.target).attr('data-task-selected',1)">false.unselectTaskEvent.notify({
taskIndex: taskIndex
});
}
},show: .buildList();
},buildList: var tasks = .model.getTasks();
var html = "";
var $tasksContainer = .$tasksContainer;
$tasksContainer.html(''var index = 0var task tasks) {
if (tasks[task].taskStatus == 'completed') {
html = "<div style='color:green; text-decoration:line-through'>";
} {
html = "<div>";
}
$tasksContainer.append(html + "<label><input type='checkbox' class='js-task' data-index='" + index + "' data-task-selected='false'>" + tasks[task].taskName + "</label></div>");
index++;
}
}, -------------------- Handlers From Event Dispatcher ----------------- */
clearTaskTextBox: this.$taskTextBox.val('');
},addTask: .show();
},1)">.show();
},1)">.show();
}
-------------------- End Handlers From Event Dispatcher -----------------
};
var TaskController = (model,view) {
this.view = view;
.init();
};
TaskController.prototype = no need to create children inside the controller
this is a job for the view
you could all as well leave this function out
() {
// 为什么绑定this没理解,不绑定就会出现this.model未定义,是不是在赋值的时候出现this的指向的变化????
this.selectTaskHandler = this.selectTask.bind(this.unselectTaskHandler = this.unselectTask.bind(this.completeTaskHandler = this.completeTask.bind(this.deleteTaskHandler = this.deleteTask.bind(this.view.addTaskEvent.attach(this.view.completeTaskEvent.attach(.completeTaskHandler);
this.view.deleteTaskEvent.attach(.deleteTaskHandler);
this.view.selectTaskEvent.attach(.selectTaskHandler);
this.view.unselectTaskEvent.attach(.unselectTaskHandler);
(sender,args) {
.model.addTask(args.task);
},selectTask: .model.setSelectedTask(args.taskIndex);
},1)">.model.unselectTask(args.taskIndex);
},completeTask: .model.setTasksAsCompleted();
},deleteTask: .model.deleteTasks();
}
};
$(var model = new TaskModel(),view = TaskView(model),controller = TaskController(model,view);
});
this.model.addTaskEvent.attach(this.addTaskHandler);