昨天說功能加越多網頁會越來越難管理有以下原因
Server
用 API 溝通時要一直去翻 DOM
裡面的資料,大部分的時間會做 DOM 轉換成 object 的處理依照昨天寫的 code
View 跟 Data(Model) 都綁在 View 上,所以維護和加新功能會比較麻煩,那如果試試看用頁面上的 MVC 看能不能改善
這邊的 MVC 跟傳統網頁的在講得有一點不一樣,不過暫時找不到合適的名詞,而邏輯上差不多,所以姑且稱之為 MVC
資料的模型,在這邊通常是 API 或 TodoList 上的物件
業務邏輯,可以將 model 的 data 印在模板上,當使用者對 UI 進行操作,Controller 會對 Model 進行更改,因為 Model 更新了 Controller 也會對 View 進行更新
有著 template 模板樣式,讓 Controller 可以簡單的使用它來做 Render
以這個為例 code
Model
var data = [];
function TodoItem(content, check) {
this.content = content;
this.check = Boolean(check);
this.time = new Date();
};
TodoItem.prototype.getTime = function() {
return this.time.toDateString();
};
TodoItem.prototype.toggle = function () {
return this.check = !this.check;
};
做了一個 TodoItem
的類別有什麼新的待辦事項就往 data 塞
那這個 data 就是我們的 Model 了
View
很簡單的模板做法
var view = '<li class="{{check}}" data-i="{{i}}"><span class="todo-content">{{content}}</span><span class="close">x</span></li>';
用了類似 mustache 的做法,有了這個 template 我們只要修改它, controller 就很簡單的更改了!
Controller
function TodoController({ view, data, bindId }) {
this.data = data;
this.view = view;
this.element = document.querySelector(bindId);
}
TodoController.prototype.addTodo = function(content, checked) {
this.data.push(new TodoItem(content, checked))
this.render();
}
TodoController.prototype.deleteItem = function (index) {
this.data.splice(index, 1);
this.render();
}
TodoController.prototype.checkItem = function (index) {
this.data[index].toggle();
this.render();
}
TodoController.prototype.render = function () {
var renderViewText = this.view,
i,
length = this.data.length,
item,
checkValue
resultView = '';
this.empty();
// set values, skip sanitize text for now...
for (i = 0; i < length; i += 1) {
item = this.data[i];
renderViewText = this.view;
checkValue = item.check ? 'checked' : '';
renderViewText = renderViewText.replace('{{check}}', checkValue);
renderViewText = renderViewText.replace('{{content}}', item.content);
renderViewText = renderViewText.replace('{{i}}', i);
resultView += renderViewText;
}
this.element.innerHTML = resultView;
}
TodoController.prototype.empty = function () {
while (this.element.firstChild) {
this.element.removeChild(this.element.firstChild);
}
}
TodoController.prototype.registerEvent = function (eventType, callback) {
if (typeof callback === 'function') {
this.element.addEventListener(eventType, callback, false);
}
}
Controller 只是我做出的概念想法,所以要讓他壞掉也是很容易的!
Controller 會在每次物件被更新的時候,將整個列表做更新
在 render 的 function
剛開始跑 empty
的 method,有注意到這麼使用 while loop
一個一個把 firstChild 移除 jsperf 說這樣比較快 就跟著做(有興趣可以自己試試看,哪個比較快!)
接下來把 data
跑過一遍然後產生出要 render 的 string
眼尖的朋友有沒有發現,雖然這樣 code
很好讀,也很直覺,但是 render
function 直覺看一定沒有先前寫的速度快,這邊想要晚點回來研究探討