Building a Todo app with Knockout.js
這是我首次嘗試用Knockout-JS建立一個待辦事項應用。Knockout-JS是一個JavaScript庫,它簡化了複雜的基於數據的用戶界面的創建。它可以單獨使用或與其他庫,如jQuery的使用。它的主要目的是UI元素綁定到定義為JavaScript對象的底層數據模型,例如,當更改了UI製作,模型更新,反之亦然。
Knockout有助於在Web應用程序的客戶端行為使用模型 - 視圖 - 視圖模型(MVVM -Model-View-ViewModel)模式。與Knockout的MVVM執行工作時,一個人必須學會的兩個主要概念是觀測(Observables)和綁定(Bindings)。。
讓我們開始.您可以按照從我的GitHub庫的步驟本教程
如果你不熟悉KnockoutJS,那麽我會強烈建議閱讀Knockout完整的Tutorial教程.
Thinking in components
Todo List待辦事項應用的功能是記錄代辦事項,簡單到不需要本地存儲,所有的代辦事項都只是存儲在內存中,就是只有程序打開的時候可以增加、修改、查看、更新和刪除代辦事項
根據以上敘述可以知道這個待辦事項應用要有基本的CRUD (Create-Read-Update-Delete)功能,還要能儲存代辦事項功能。
我就根據這樣的需求來建立Knockout.js待辦事項應用程序
Step1 – build ViewModel
建設Knockout.js應用的主要先建立ViewModel,建立ViewModel之前先將Todo項目轉成物件。
Todo object
var Todo = function(title, completed){
this.title = ko.observable(title); //待辦事項標題
this.completed = ko.observable(completed); //待辦事項是否完成 True: 完成 False: 未完成
this.editing = ko.observable(false); //是否編輯中 True: 編輯中
};
我用Array方式來存放待辦事項
ViewModel:
var ViewModel = function(todos){
this.todos = ko.observableArray(todos.map(function(todo){
return new Todo(todo.title, todo.completed);
}));
};
Step1 – Add function
宣告一個變數current並綁定在input控件 : value 綁定是關聯DOM元素的值到view model的屬性上。當用戶編輯表單控件的時候, view model對應的屬性值會自動更新。同樣,當你更新view model屬性的時候,相對應的元素值在頁面上也會自動更新。
value 綁定有一個主要參數(Value)和其他參數(valueUpdate)
介面
![TodoListApp](/images/knockoutjs_1_1.png)
index.html:
<input class="todoField" id="new-todo" data-bind="value: current, valueUpdate: 'afterkeydown', enterKey: add" placeholder="What needs to be done?" autofocus>
valueUpdate
如果你使用valueUpdate參數,那就是意味著KO將使用自定義的事件而不是默認的離開焦點事件。下面是一些最常用的選項:
“change”(默認值) - 當失去焦點的時候更新view model的值,或者是
“keyup” – 當用戶敲完一個字符以後立即更新view model。
“keypress” – 當用戶正在敲一個字符但沒有釋放鍵盤的時候就立即更新view model。不像 keyup,這個更新和keydown是一樣的。
“afterkeydown” – 當用戶開始輸入字符的時候就更新view model。主要是捕獲瀏覽器的keydown事件或異步handle事件。
上述這些選項,如果你想讓你的view model進行實時更新,使用“afterkeydown”是最好的選擇。 更多的請參考http://knockoutjs.com/documentation/value-binding.html
當用戶按下Enter時,就會呼叫add function,在此會建立新的Todo並放入清單中。
App.js:
this.current = ko.observable();
this.add = function(){
var current = this.current().trim();
if(current){
this.todos.push(new Todo(current,false));
this.current('');
}
}.bind(this);
Step2 – Display Todo list
在顯示待辦事項時,用三個控件(checkbox、lable、button)組成一個待辦事項控件,而在每一個控件也綁定一個:
checkbox : 讓用戶決定是否已完成
lable : 顯示待辦事項標題
button : 讓用戶可以刪除待辦事項
在knockoutjs可以使用迴圈方式來建立控件,也就是樣板的概念,所以綁定ul時我用foreach方式來建立待辦事項控件。
介面
![TodoListApp](/images/knockoutjs_1_2.png)
index.html:
<ul id="todo-list" data-bind="foreach: todos()">
<li data-bind="css: { completed: completed, editing: editing }">
<div class="view">
<input class="todoCheckbox" data-bind="checked: completed" type="checkbox" >
<label data-bind="text: title, event: { dblclick: $root.editItem }, css: {textDecoration:completed()==true}" ></label>
<button class="close pull-right" data-bind="click: $root.remove">×</button>
</div>
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.saveEditing, escapeKey: $root.cancelEditing, selectAndFocus: editing, event: { blur: $root.saveEditing }">
</li>
</ul>
Step2 – Edit 、 Update and Delete Todo item
在待辦事項控件裡,要綁定完成待辦事項、編輯、更新及刪除功能。
綁定編輯功能(editItem)時,我使用double click 事件 : dblclick: $root.editItem,當用戶雙擊控件時,label控件會消失而input控件會出現,而這個input控件上也綁定了更新與取消空功能。
綁定完成待辦事項(completed),綁定在checked 事件 : checked: completed,在同時更新view model時,我也特定在label的CSS也綁定css: {textDecoration:completed()==true},所以當完成待辦事項時就會出現刪除線。
綁定刪除功能(remove),綁定在click 事件 :click: $root.remove
index.html:
<ul id="todo-list" data-bind="foreach: todos()">
<li data-bind="css: { completed: completed, editing: editing }">
<div class="view">
<input class="todoCheckbox" data-bind="checked: completed" type="checkbox" >
<label data-bind="text: title, event: { dblclick: $root.editItem }, css: {textDecoration:completed()==true}" ></label>
<button class="close pull-right" data-bind="click: $root.remove">×</button>
</div>
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.saveEditing, escapeKey: $root.cancelEditing, selectAndFocus: editing, event: { blur: $root.saveEditing }">
</li>
</ul>
App.js:
// delete function
this.remove = function(todo){
this.todos.remove(todo);
}.bind(this);
// edit function
this.editItem = function(item){
item.editing(true);
item.previousTitle = item.title();
}.bind(this);
// save function
this.saveEditing = function(item){
item.editing(false);
var title = item.title();
var trimmedTitle = title.trim();
if(title !== trimmedTitle){
item.title(trimmedTitle);
}
if(!trimmedTitle){
this.remove(item);
}
}.bind(this);
// cancel function
this.cancelEditing = function(item){
item.editing(false);
item.title(item.previousTitle);
}.bind(this);
// save function
ko.computed(function(){
localStorage.setItem('todos-knockoutjs', ko.toJSON(this.todos));
}.bind(this)).extend({
rateLimit: {timeout: 500, method: 'notifyWhenChangesStop'}
});
當你完成,你可以看到 TodoApp.
The complete working demo can be found here .
##Building a Todo app with Knockout.js (1) - A simple todo list
##Building a Todo app with Knockout.js (2) - Filter、Search and Sortable function