隨着JavaScript程序變得愈來愈複雜,每每須要一個團隊協做開發,這時代碼的模塊化和組織規範就變得異常重要了。MVC模式就是代碼組織的經典模式。backbone.js就是爲前端開發提供MVC模式滴!css
官網左側菜單欄裏面就是backbone.js的所有模塊了html
在使用backbone.js的時候,必須引入underscore.js。
此外在官網上面都會給出代碼示例,在代碼的右上角上,有一個運行的按鈕,點擊的運行就能夠看到這段代碼運行的結果啦。前端
因爲網頁編程不一樣於客戶端編程,在MVC的基礎上,JavaScript社區產生了各類變體框架MVP(Model-View-Presenter)、MVVM(Model-View-ViewModel)等等,有人就把全部這一類框架的各類模式統稱爲MV*。ajax
框架的優勢在於合理組織代碼、便於團隊合做和將來的維護,缺點在於有必定的學習成本,且限制你只能採起它的寫法。數據庫
$(function(){ var User = Backbone.Model.extend({ defaults : { name : 'tom' } }); var View = Backbone.View.extend({ initialize : function(){ console.log("initialize"); this.listenTo( this.model , 'change' , this.show ); // 當與這個view綁定的model數據發生變化的時候,調用show方法 }, show : function(model){ // 向頁面中輸出信息 $('body').append( '<div>'+ this.model.get('name')+ '</br>也能夠經過參數調用</br>' + model.get('name') +'</div>' ); } }); var tom = new User; var view = new View({model:tom}); // 建立view實體 setTimeout(function(){ tom.set('name','jack'); // 修改數據 }, 1000); // 一秒後修改數據,觸發show });
listenTo容許一個對象監聽另外一個對象的事件,上面的代碼就是讓view監聽model的change事件,而後調用show()
方法編程
var tom = new Backbone.Model({'name':'tom'}); // 建立學生tom var peter = new Backbone.Model({'name':'peter'}); // 建立學生peter var students = new Backbone.Collection(); // tom和peter都是學生 students.add( tom ); // 向Collection中添加學生 students.add( peter ); console.log( JSON.stringify(students) ); //[{"name":"tom"},{"name":"peter"}]
用new的方式建立了兩個Model的實例;經過json對象傳參方式給Model的constuctor構造函數傳遞了name屬性。
用new的方式建立了一個Collection實例;調用students的add方法,將tom和peter添加到集合中。
在文檔中能夠看出,使用{'name':'tom'}
這種方式給Model設置的屬性,實際上會調用model.set()方法。json
var User = Backbone.Model.extend({ sayHello : function(){ //實例方法 console.log("hello"); } }, { sayWorld : function(){ //靜態方法 console.log("world"); } }); var tom = new User; // 建立一個用戶 tom.sayHello(); // 調用用戶的實例方法 User.sayWorld(); // 直接調用Model的靜態方法
使用extend擴展Backbone.Model,第一個參數是實例對象中的屬性,第二個可選的參數會直接註冊到構造函數成爲靜態方法。這樣即便沒有實例化對象,也能調用Model中定義的方法瀏覽器
var User = Backbone.Model.extend({ defaults : { // 默認屬性,可是子類也會繼承 "name": "tom" }, sayHello : function(){ // 父類的方法 console.log("hello"); } }); var ChildUser = User.extend({ // ChildUser 繼承自User sayChild : function(){ // 子類的方法 console.log("child"); } }); var child = new ChildUser; // 建立ChildUser實例 child.sayHello(); // 子類繼承父類sayHello()方法 child.sayChild(); // 子類本身的方法 console.log(child.get("name")); // 子類繼承父類屬性
extend會正確的設置原型鏈,因此能夠經過extend實現繼承。上面的代碼就是建立父類User,而後子類ChildUser繼承子父類。子類會繼承父類的屬性和方法服務器
var User = Backbone.Model.extend({ defaults : { name : 'tom' // 默認的名字 }, initialize : function(){ //當model建立的時候,調用 console.log("initialize"); this.on('change',function(){ // 當數據發生變化的時候觸發 console.log("此時個人名字是:"+this.get("name")); }); } }); var tom = new User; tom.set('name','jack'); // 修改模型的數據,會被change檢測到
若是指定了initialize
方法,會在建立實例對象以後調用initialize()
。
當修改了模型數據(經過set()
方法修改數據),會觸發自定義事件。app
var User = Backbone.Model.extend({ defaults : { name : 'tom', // 默認的名字 age : 10 }, initialize : function(){ //當model建立的時候,調用 console.log("initialize"); this.on('change:name',function(){ // 只檢測name的變化 console.log("此時個人名字是:"+this.get("name")); }); } }); var tom = new User; tom.set('name','jack'); // 修改模型的數據,會被change檢測到 tom.set('age','20');// 修改年齡不會被change檢測
若是隻想檢測某個屬性的變化,能夠經過添加命名空間的方式區別開事件。經過:
的方式給事件添加命名空間。
var BodyView = Backbone.View.extend({ el : $('body'), // 若是沒有指定el,el就會是個空div events : { 'click input' : 'sayHello', // 點擊input的時候調用sayHello方法 'mouseover li' : 'moveLi'// 鼠標懸浮li標籤的時候調用moveLi方法 }, sayHello : function(){ console.log("Hello"); }, moveLi : function(){ console.log("mouseover li"); } }); var view = new BodyView;
若是設置了tagName、className、id、attributes屬性(爲視圖設置根元素),那麼view.el
就會被建立,若是沒有指定view.el
就是個空的div。
Backbone.events能夠寫成對象的形式,給視圖綁定一組自定義事件。
var Name = Backbone.Model.extend({ defaults : { name : 'tom' } }); var NameView = Backbone.View.extend({ initialize : function(){ this.listenTo( this.model , 'change' , this.showName ); }, showName : function(model){ // $('body').append( "<div>" + model.get("name") + "</div>" ); // 不使用template的時候html代碼與js寫在一塊兒 $('body').append( this.template(this.model.toJSON()) ); // 使用模版以後,html代碼與js代碼相分離 }, template: _.template($('#name').html()) // _.template中傳入須要編譯的模版 // 返回的結果就是編譯後的html代碼 // 最後在showName中調用,將編譯後的html顯示到body中 }); var name = new Name; var nameView = new NameView({model:name}); name.set('name','jack'); <script type="text/template" id="name"> <% for (var i=0;i<5;i++) { %> <div><%= name %></div> <% } %> </script>
使用js模版不只能夠將html代碼和js代碼分離,提升可讀性,也能提升開發效率。backbone.js使用的underscore.js中的template
Backbone.sync = function(method, model) { console.log(method + ": " + JSON.stringify(model)); model.set('id', 1); // 模型的特殊屬性 }; var Book = Backbone.Model.extend({ defaults:{ title: "The Rough Riders", author: "Theodore Roosevelt" } }); var b = new Book; b.save(); // create: {"title":"The Rough Riders","author":"Theodore Roosevelt"} b.save({author: "Teddy"}); // update: {"title":"The Rough Riders","author":"Teddy","id":1}
調用模型的save方法,就是委託Backbone.sync對數據進行持久化處理(保存到數據庫),若是驗證成功返回jqXHR,不然返回false。
sync默認狀況下是使用的是jQuery.ajax,能夠經過重寫sync來使用其餘方式進行持久化處理。如WebSockets,XML,或者Local Storage。
上面的代碼就是重寫Backbone.sync的過程。第一次save
的時候發送的create請求,第二次save的時候發送的是update
請求。
Backbone是如何區分第一次請求仍是第二次請求的呢?
是根據經過model.isNew
這個方法進行判斷的。若是模型沒有id屬性,就是表示模型是新模型。能夠經過下面的代碼進行測試
Backbone.sync = function(method, model) { console.log(method + ": " + JSON.stringify(model)); console.log(model.isNew()); // 此時不存在id屬性,因此是true model.set('id', 1); // 模型的特殊屬性 console.log(model.isNew()); // 此時存在id屬性,因此是false };
在Model.id文檔中指出,若是經過set設置了model的id,就會將這個id拷貝到模型上,做爲model的直接屬性。在下圖中能夠發現經過Model.set('id',1)
,給attributes中添加了id屬性,也直接給model添加了id屬性。
可是相反的,若是用model.id=1
的方式直接給model添加id屬性,是不會拷貝到attributes中的。若是隻是給model直接添加了id,Model.isNew
返回的一直都會是true。
Backbone.sync = function(method, model) { console.log(method + ": " + JSON.stringify(model)); console.log(model.isNew()); // 返回true model.id=1; // 給model直接添加id屬性 console.log(model.isNew()); // 返回true };