[轉]backbone.js 初探

本文轉自:http://weakfi.iteye.com/blog/1391990javascript

什麼是backbone

backbone不是脊椎骨,而是幫助開發重量級的javascript應用的框架。html

主要提供了3個東西:一、models(模型) 二、collections(集合) 三、views(視圖)java

backbone.js文件自己很小,壓縮後只有5.3KB,做爲一個框架級別的核心JS文件,這個數字很可怕。jquery

除此以外,這個JS還必須依賴於另外一個JS文件:underscore.js(包含許多工具方法,集合操做,js模板等等)。數據庫

 

簡介

用Backbone.Model表示應用中全部數據,models中的數據能夠建立、校驗、銷燬和保存到服務端。json

當models中值被改變時自動觸發一個"change"事件、全部用於展現models數據的views都會偵聽到這個事件,而後進行從新渲染。app

Backbone.Collection和咱們平時接觸的JAVA集合類類似,具備增長元素,刪除元素,獲取長度,排序,比較等一系列工具方法,說白了就是一個保存models的集合類。框架

Backbone.View中能夠綁定dom el和客戶端事件。頁面中的html就是經過views的render方法渲染出來的,當新建一個view的時候經過要傳進一個model做爲數據,例如:dom

 

Js代碼 複製代碼  收藏代碼
  1. var view = new EmployeeView({model:employee});  
var view = new EmployeeView({model:employee});

 也就是說model就是以這種方式和view進行關聯的。工具

 

特色

建立models或者views的語法:extends,至關於類繼承

models的建立,銷燬,校驗等一系列改變都會觸發相應的事件

 

示例

需求:用backbone.js和jquery實現一個可編輯的員工信息表格。

功能:一、錄入員工信息。二、刪除員工信息。三、雙擊表格可對員工信息進行修改。四、能對員工信息進行有效性校驗。五、能對員工信息進行持久化。

設計:

用Employee類(繼承自Backbone.Model)表示員工信息,包含ID、姓名、性別、年齡和職位字段。

 

 

Js代碼 複製代碼  收藏代碼
  1. window.Employee = Backbone.Model.extend({  
  2.     // 模型值校驗  
  3.     validate:function(attrs){  
  4.         for(var key in attrs){  
  5.             if(attrs[key] == ''){  
  6.                 return key + "不能爲空";  
  7.             }  
  8.             if(key == 'age' && isNaN(attrs.age)){  
  9.                 return "年齡必須是數字";  
  10.             }  
  11.         }  
  12.     }  
  13. });  
	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 "年齡必須是數字";
				}
			}
		}
	});

聲明Employee類以後就能夠新增一個Employee的示例對象了:

 

Js代碼 複製代碼  收藏代碼
  1. var employee = new Employee();  
var employee = new Employee();

 

Employee類中沒必要聲明ID、姓名等業務字段。當須要給employee設置這些信息時候,只須要調用

 

Js代碼 複製代碼  收藏代碼
  1. employee.set({'id':1,'name':'Jason'});  
employee.set({'id':1,'name':'Jason'});

 

固然,若是須要對employee的信息進行校驗,須要給Employee類配置一個validate方法,這個方法的參數attrs就是set進去的json數據。這樣,當employee裏面的數據每次發生改變的時候都會先調用這個validate方法。

 

Model類定義好以後就能夠開始定義集合類了,在集合類裏面能夠對裏面的每一個Model進行增長,刪除等一系列操做,還能夠調用fetch方法從server端獲取集合的初始值。

 

Js代碼 複製代碼  收藏代碼
  1. window.EmployeeList = Backbone.Collection.extend({  
  2.     model : Employee,  
  3.     // 持久化到本地數據庫  
  4.     localStorage: new Store("employees"),  
  5.       
  6. });  
  7. window.Employees = new EmployeeList();  
	window.EmployeeList = Backbone.Collection.extend({
		model : Employee,
		// 持久化到本地數據庫
		localStorage: new Store("employees"),
		
	});
	window.Employees = new EmployeeList();

 

設置 localStorage屬性後Employees裏面的數據自動會同步保存到本地數據庫裏面,每當調用Employees.fetch()後又會從localStorage裏面恢復數據。

 

View類主要負責一切和界面相關的工做,好比綁定html模板,綁定界面元素的事件,初始的渲染,模型值改變後的從新渲染和界面元素的銷燬等:

 

Js代碼 複製代碼  收藏代碼
  1. window.EmployeeView = Backbone.View.extend({  
  2.         tagName : 'tr',  
  3.         template : _.template($('#item-template').html()),  
  4.         events : {  
  5.             "dblclick td" : "edit",  
  6.             "blur input,select" : "close",  
  7.             "click .del" : "clear",  
  8.         },  
  9.         initialize : function(){  
  10.             // 每次更新模型後從新渲染  
  11.             this.model.bind('change', this.render, this);  
  12.             // 每次刪除模型以後自動移除UI  
  13.             this.model.bind('destroy', this.remove, this);  
  14.         },  
  15.         setText : function(){  
  16.             var model = this.model;  
  17.             this.input = $(this.el).find('input,select');   
  18.             this.input.each(function(){  
  19.                 var input = $(this);  
  20.                 input.val(model.get(input.attr("name")));  
  21.             });  
  22.         },  
  23.         close: function(e) {  
  24.             var input = $(e.currentTarget);  
  25.             var obj = {};  
  26.             obj[input.attr('name')] = input.val();  
  27.             this.model.save(obj);  
  28.             $(e.currentTarget).parent().parent().removeClass("editing");  
  29.         },  
  30.         edit : function(e){  
  31.             // 給td加上editing樣式  
  32.             $(e.currentTarget).addClass('editing').find('input,select').focus();  
  33.         },  
  34.         render: function() {  
  35.             $(this.el).html(this.template(this.model.toJSON()));  
  36.             // 把每一個單元格的值賦予隱藏的輸入框  
  37.             this.setText();  
  38.             return this;  
  39.         },  
  40.         remove: function() {  
  41.             $(this.el).remove();  
  42.         },  
  43.         clear: function() {  
  44.           this.model.destroy();  
  45.         }  
  46.     });  
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對象的時候都會先調用initialize方法,這個方法裏面綁定的事件確保了tr元素對應的model值每次發生改變或者被刪除時都會同步到界面。也就是說當每次操做界面對數據進行修改後都是先把當前的變動保存到view綁定的model對象裏面,而後model裏面的事件機制會自動觸發一個"change"事件對界面進行修改。

 

 

template中使用的方法_.template($('#item-template').html())是前面提到的underscore.js中提供一個工具方法,能夠經過界面的HTML模板和一個JSON生成動態的HTML,說白了就是把JSON裏面的值填充到HTML模板中對應的佔位符裏面去,牛X的是HTML模板裏面支持一些經常使用的邏輯表達式如if,else,foreach等:

 

Html代碼 複製代碼  收藏代碼
  1.   <script type="text/template" id="item-template">  
  2. <td><%= eid %></td>  
  3. <td class="username">  
  4.     <div class="display"><%= username %></div>  
  5.     <div class="edit"><input class="username" name="username"></input></div>  
  6. </td>  
  7. <td class="sex">  
  8.     <div class="display"><%= sex=="1" ? "女":"男" %></div>  
  9.     <div class="edit">  
  10.     <select name="sex" class="sex" style="width:45px">  
  11.         <option value="0">男</option><option value="1">女</option>  
  12.     </select>  
  13.     </div>  
  14. </td>  
  15. <td class="age">  
  16.     <div class="display"><%= age %></div>  
  17.     <div class="edit">  
  18.         <input class="age" name="age"></input>  
  19.     </div>  
  20. </td>  
  21. <td class="position">  
  22.     <div class="display"><%= position %></div>  
  23.     <div class="edit">  
  24.         <input class="position" name="position"></input>  
  25.     </div>  
  26. </td>  
  27. <td>  
  28.     <href="#" class="del">刪除</a>  
  29. </td>  
  30.     </script>  
	    <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裏面的數據設置到每一個tr裏面的隱藏輸入域裏面。

 

close方法被綁定到了input和select元素的blur事件中。當用戶對單元格數據進行修改後都會把鼠標點擊到界面其餘地方而後輸入框會自動隱藏而且把修改的數據顯示在表格上面。close方法首先從當前被編輯的元素中拿到最新值,而後封裝成一個對象,調用model的save方法後首先執行model的validate方法,若是校驗經過則保存到本地存儲並觸發"change"事件。

 

最後還須要一個主界面View,這個View主要綁定了界面中的錄入表單的「增長」按鈕事件,Employees的相關事件以及頁面初始化時從本地存儲中恢復數據:

 

Js代碼 複製代碼  收藏代碼
  1. window.AppView = Backbone.View.extend({  
  2.         el : $("#app"),  
  3.         events : {  
  4.             "click .#add-btn" : "createOnEnter"  
  5.         },  
  6.         // 綁定collection的相關事件  
  7.         initialize: function() {  
  8.             Employees.bind('add', this.addOne, this);  
  9.             // 調用fetch的時候觸發reset  
  10.             Employees.bind('reset', this.addAll, this);  
  11.             Employees.fetch();  
  12.         },  
  13.         createOnEnter : function(e) {  
  14.             var employee = new Employee();  
  15.             var attr = {};  
  16.             $('#emp-form input,#emp-form select').each(function(){  
  17.                 var input = $(this);  
  18.                 attr[input.attr('name')] = input.val();  
  19.             });  
  20.             employee.bind('error',function(model,error){  
  21.                 alert(error);  
  22.             });  
  23.             // set方法中會自動調用model的validate方法進行校驗,若是不經過則返回false  
  24.             if(employee.set(attr)){  
  25.                 Employees.create(employee);  
  26.             }  
  27.         },  
  28.         addOne : function(employee){  
  29.             employee.set({"eid":employee.get("eid")||Employees.length});  
  30.             employee.bind('error',function(model,error){  
  31.                 alert(error);  
  32.             });  
  33.             var view = new EmployeeView({model:employee});  
  34.             $(".emp-table tbody").append(view.render().el);  
  35.         },  
  36.         addAll : function(){  
  37.             Employees.each(this.addOne);  
  38.         }  
  39.     });  
window.AppView = Backbone.View.extend({
		el : $("#app"),
		events : {
			"click .#add-btn" : "createOnEnter"
		},
		// 綁定collection的相關事件
		initialize: function() {
	        Employees.bind('add', this.addOne, this);
	        // 調用fetch的時候觸發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方法中會自動調用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的時候都會調用AppView的addOne方法,這個方法主要綁定了model的error事件以及把EmployeeView生成的html插入到界面中的合適位置。

 

OK,萬事俱備,只欠啓動,整個應用的初始化方法就是AppView的initialize方法,所以只須要新建一個AppView就能夠了:

 

Js代碼 複製代碼  收藏代碼
  1. window.App = new AppView();  
window.App = new AppView();

 

 

整個示例的JS代碼不多,加上註釋只有100行左右,感興趣的能夠下載看看。因爲示例使用到了本地存儲,因此不要用IE運行示例,你懂的。

 

相關文章
相關標籤/搜索