JavaScript MVC框架backbone.js初探
什么是backbone
backbone不是脊椎骨,而是幫助開發(fā)重量級的javascript應用的框架。
主要提供了3個東西:1、models(模型) 2、collections(集合) 3、views(視圖)
backbone.js文件本身很小,壓縮后只有5.3KB,作為一個框架級別的核心JS文件,這個數(shù)字很可怕。
除此之外,這個JS還必須依賴于另一個JS文件:underscore.js(包含許多工具方法,集合操作,js模板等等)。
簡介
用Backbone.Model表示應用中所有數(shù)據(jù),models中的數(shù)據(jù)可以創(chuàng)建、校驗、銷毀和保存到服務端。
當models中值被改變時自動觸發(fā)一個"change"事件、所有用于展示models數(shù)據(jù)的views都會偵聽到這個事件,然后進行重新渲染。
Backbone.Collection和我們平時接觸的JAVA集合類相似,具有增加元素,刪除元素,獲取長度,排序,比較等一系列工具方法,說白了就是一個保存models的集合類。
Backbone.View中可以綁定dom el和客戶端事件。頁面中的html就是通過views的render方法渲染出來的,當新建一個view的時候通過要傳進一個model作為數(shù)據(jù),例如:
Js代碼:
- var view = new EmployeeView({model:employee});
也就是說model就是以這種方式和view進行關聯(lián)的。
特點
創(chuàng)建models或者views的語法:extends,相當于類繼承
models的創(chuàng)建,銷毀,校驗等一系列改變都會觸發(fā)相應的事件
示例
需求:用backbone.js和jquery實現(xiàn)一個可編輯的員工信息表格。
功能:1、錄入員工信息。2、刪除員工信息。3、雙擊表格可對員工信息進行修改。4、能對員工信息進行有效性校驗。5、能對員工信息進行持久化。
設計:
用Employee類(繼承自Backbone.Model)表示員工信息,包含ID、姓名、性別、年齡和職位字段。
Js代碼:
- window.Employee = Backbone.Model.extend({
- // 模型值校驗
- validate:function(attrs){
- for(var key in attrs){
- if(attrs[key] == ''){
- return key + "不能為空";
- }
- if(key == 'age' && isNaN(attrs.age)){
- return "年齡必須是數(shù)字";
- }
- }
- }
- });
聲明Employee類之后就可以新增一個Employee的示例對象了:
Js代碼:
- var employee = new Employee();
Employee類中不必聲明ID、姓名等業(yè)務字段。當需要給employee設置這些信息時候,只需要調(diào)用
Js代碼:
- employee.set({'id':1,'name':'Jason'});
當然,如果需要對employee的信息進行校驗,需要給Employee類配置一個validate方法,這個方法的參數(shù)attrs就是set進去的json數(shù)據(jù)。這樣,當employee里面的數(shù)據(jù)每次發(fā)生改變的時候都會先調(diào)用這個validate方法。
Model類定義好之后就可以開始定義集合類了,在集合類里面可以對里面的每個Model進行增加,刪除等一系列操作,還可以調(diào)用fetch方法從server端獲取集合的初始值。
Js代碼:
- window.EmployeeList = Backbone.Collection.extend({
- model : Employee,
- // 持久化到本地數(shù)據(jù)庫
- localStorage: new Store("employees"),
- });
- window.Employees = new EmployeeList();
設置 localStorage屬性后Employees里面的數(shù)據(jù)自動會同步保存到本地數(shù)據(jù)庫里面,每當調(diào)用Employees.fetch()后又會從localStorage里面恢復數(shù)據(jù)。
View類主要負責一切和界面相關的工作,比如綁定html模板,綁定界面元素的事件,初始的渲染,模型值改變后的重新渲染和界面元素的銷毀等:
Js代碼:
- window.EmployeeView = Backbone.View.extend({
- tagName : 'tr',
- template : _.template($('#item-template').html()),
- events : {
- "dblclick td" : "edit",
- "blur input,select" : "close",
- "click .del" : "clear",
- },
- initialize : function(){
- // 每次更新模型后重新渲染
- this.model.bind('change', this.render, this);
- // 每次刪除模型之后自動移除UI
- this.model.bind('destroy', this.remove, this);
- },
- setText : function(){
- var model = this.model;
- this.input = $(this.el).find('input,select');
- this.input.each(function(){
- var input = $(this);
- input.val(model.get(input.attr("name")));
- });
- },
- close: function(e) {
- var input = $(e.currentTarget);
- var obj = {};
- obj[input.attr('name')] = input.val();
- this.model.save(obj);
- $(e.currentTarget).parent().parent().removeClass("editing");
- },
- edit : function(e){
- // 給td加上editing樣式
- $(e.currentTarget).addClass('editing').find('input,select').focus();
- },
- render: function() {
- $(this.el).html(this.template(this.model.toJSON()));
- // 把每個單元格的值賦予隱藏的輸入框
- this.setText();
- return this;
- },
- remove: function() {
- $(this.el).remove();
- },
- clear: function() {
- this.model.destroy();
- }
- });
這個類里面的代碼比較多,但主要和界面的渲染有關。一個EmployeeView對象對應table里面的一個tr元素。每次new一個EmployeeView對象的時候都會先調(diào)用initialize方法,這個方法里面綁定的事件確保了tr元素對應的model值每次發(fā)生改變或者被刪除時都會同步到界面。也就是說當每次操作界面對數(shù)據(jù)進行修改后都是先把當前的變更保存到view綁定的model對象里面,然后model里面的事件機制會自動觸發(fā)一個"change"事件對界面進行修改。
template中使用的方法_.template($('#item-template').html())是前面提到的underscore.js中提供一個工具方法,可以通過界面的HTML模板和一個JSON生成動態(tài)的HTML,說白了就是把JSON里面的值填充到HTML模板中對應的占位符里面去,牛X的是HTML模板里面支持一些常用的邏輯表達式如if,else,foreach等:
Html代碼:
- <script type="text/template" id="item-template">
- <td><%= eid %></td>
- <td class="username">
- <div class="display"><%= username %></div>
- <div class="edit"><input class="username" name="username"></input></div>
- </td>
- <td class="sex">
- <div class="display"><%= sex=="1" ? "女":"男" %></div>
- <div class="edit">
- <select name="sex" class="sex" style="width:45px">
- <option value="0">男</option><option value="1">女</option>
- </select>
- </div>
- </td>
- <td class="age">
- <div class="display"><%= age %></div>
- <div class="edit">
- <input class="age" name="age"></input>
- </div>
- </td>
- <td class="position">
- <div class="display"><%= position %></div>
- <div class="edit">
- <input class="position" name="position"></input>
- </div>
- </td>
- <td>
- <a href="#" class="del">刪除</a>
- </td>
- </script>
setText方法主要負責把model里面的數(shù)據(jù)設置到每個tr里面的隱藏輸入域里面。
close方法被綁定到了input和select元素的blur事件中。當用戶對單元格數(shù)據(jù)進行修改后都會把鼠標點擊到界面其他地方然后輸入框會自動隱藏并且把修改的數(shù)據(jù)顯示在表格上面。close方法首先從當前被編輯的元素中拿到最新值,然后封裝成一個對象,調(diào)用model的save方法后首先執(zhí)行model的validate方法,如果校驗通過則保存到本地存儲并觸發(fā)"change"事件。
最后還需要一個主界面View,這個View主要綁定了界面中的錄入表單的“增加”按鈕事件,Employees的相關事件以及頁面初始化時從本地存儲中恢復數(shù)據(jù):
Js代碼:
- window.AppView = Backbone.View.extend({
- el : $("#app"),
- events : {
- "click .#add-btn" : "createOnEnter"
- },
- // 綁定collection的相關事件
- initialize: function() {
- Employees.bind('add', this.addOne, this);
- // 調(diào)用fetch的時候觸發(fā)reset
- Employees.bind('reset', this.addAll, this);
- Employees.fetch();
- },
- createOnEnter : function(e) {
- var employee = new Employee();
- var attr = {};
- $('#emp-form input,#emp-form select').each(function(){
- var input = $(this);
- attr[input.attr('name')] = input.val();
- });
- employee.bind('error',function(model,error){
- alert(error);
- });
- // set方法中會自動調(diào)用model的validate方法進行校驗,如果不通過則返回false
- if(employee.set(attr)){
- Employees.create(employee);
- }
- },
- addOne : function(employee){
- employee.set({"eid":employee.get("eid")||Employees.length});
- employee.bind('error',function(model,error){
- alert(error);
- });
- var view = new EmployeeView({model:employee});
- $(".emp-table tbody").append(view.render().el);
- },
- addAll : function(){
- Employees.each(this.addOne);
- }
- });
initialize方法中綁定了Employees的add和reset事件,也就是說每當往Employees中添加一個model的時候都會調(diào)用AppView的addOne方法,這個方法主要綁定了model的error事件以及把EmployeeView生成的html插入到界面中的合適位置。
OK,萬事俱備,只欠啟動,整個應用的初始化方法就是AppView的initialize方法,因此只需要新建一個AppView就可以了:
Js代碼
- window.App = new AppView();
整個示例的JS代碼很少,加上注釋只有100行左右,感興趣的可以下載看看。由于示例使用到了本地存儲,所以不要用IE運行示例,你懂的。
原文:http://www.operamasks.org/blog/?p=211
【編輯推薦】