日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Backbone.js的技巧和模式

 Backbone.js是一個(gè)開源JavaScript“MV*”框架, 在三年前它的第一次發(fā)布的時(shí)候就獲得了顯著的推動(dòng)。盡管Backbone.js為Javascript應(yīng)用程序提供了自己的結(jié)構(gòu),但它留下了大量根據(jù)開發(fā) 者的需要而使用的設(shè)計(jì)模式和決策,并且當(dāng)開發(fā)者們第一次使用Backbone.js開發(fā)的時(shí)候都會(huì)遇到許多共同的問題。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對(duì)這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、網(wǎng)頁空間、營銷軟件、網(wǎng)站建設(shè)、成都網(wǎng)站維護(hù)、網(wǎng)站推廣。

因此,在這篇文章中,我們除了會(huì)探索各種各樣你能夠應(yīng)用到你的Backbone.js應(yīng)用中的設(shè)計(jì)模式外,我們也會(huì)關(guān)注一些困惑開發(fā)者的常見問題。

執(zhí)行對(duì)象的深復(fù)制

JavaScript中所有原始類型變量的傳遞都是值傳遞。所以,當(dāng)變量被引用的時(shí)候會(huì)傳遞該變量的值。

 
 
 
 
  1. var helloWorld = “Hello World”; 
  2. var helloWorldCopy = helloWorld; 

例如,以上代碼會(huì)將helloWorldCopy 的值設(shè)為helloWorld的值。所以對(duì)于helloWorldCopy 的所有修改都不會(huì)改變helloWorld, 因?yàn)樗且粋€(gè)拷貝。另一方面,JavaScript所有非原始類型變量的傳遞都是引用傳遞,意思是當(dāng)變量被引用的時(shí)候,JavaScript會(huì)傳遞一個(gè)其內(nèi)存地址的參照。

 
 
 
 
  1. var helloWorld = { 
  2.     ‘hello’: ‘world’ 
  3. var helloWorldCopy = helloWorld; 

舉個(gè)例子,上面的代碼會(huì)將helloWorldCopy 設(shè)為helloWorld 對(duì)象的別名,此時(shí),你可能會(huì)猜到,對(duì)helloWorldCopy 的所有修改都會(huì)直接在helloWorld 對(duì)象上進(jìn)行。如果你想得到一個(gè)helloWorld 對(duì)象的拷貝,你必須對(duì)這個(gè)對(duì)象進(jìn)行一次復(fù)制。

你可能想知道,“為什么他(作者)要在這篇文章中解釋這些按引用傳遞的東西?”很好,這是因?yàn)樵?strong>Backbone.js的對(duì)象傳遞中,并不對(duì)進(jìn)行對(duì)象復(fù)制,意味著如果你在一個(gè)模型中調(diào)用 get( ) 方法來取得一個(gè)對(duì)象,那么對(duì)它的任何修改都會(huì)直接在模型中的那個(gè)對(duì)象進(jìn)行操作!讓我們通過一個(gè)例子來看看什么時(shí)候它會(huì)成為你的麻煩。假設(shè)現(xiàn)在你有一個(gè)如下的Person 模型:

 
 
 
 
  1. var Person = Backbone.Model.extend({ 
  2.    defaults: { 
  3.         'name': 'John Doe', 
  4.         'address': { 
  5.             'street': '1st Street' 
  6.             'city': 'Austin', 
  7.             'state': 'TX' 
  8.             'zipCode': 78701 
  9.         } 
  10.    } 
  11. }); 

 并且假設(shè)你創(chuàng)建了一個(gè)新的person 對(duì)象:

 
 
 
 
  1. var person = new Person({ 
  2.     'name': 'Phillip W' 
  3. }); 

現(xiàn)在讓我們對(duì)新對(duì)象person 的屬性做一點(diǎn)修改。

 
 
 
 
  1. person.set('name', 'Phillip W.'); 

上述代碼會(huì)對(duì)person 對(duì)象中的name 屬性進(jìn)行修改。接下來讓我們嘗試修改person 對(duì)象的address 屬性。在這之前,我們先對(duì)address屬性添加校驗(yàn)。

 
 
 
 
  1. var Person = Backbone.Model.extend({ 
  2.     validate: function(attributes) { 
  3.  
  4.         if(isNaN(attributes.address.zipCode)) return "Address ZIP code must be a number!"; 
  5.     }, 
  6.  
  7.     defaults: { 
  8.         'name': 'John Doe', 
  9.         'address': { 
  10.             'street': '1st Street' 
  11.             'city': 'Austin', 
  12.             'state': 'TX' 
  13.             'zipCode': 78701 
  14.         } 
  15.     }  
  16. }); 

現(xiàn)在,我們會(huì)嘗試使用一個(gè)不正確的ZIP 碼來修改對(duì)象的address 屬性。

 
 
 
 
  1. var address = person.get('address'); 
  2. address.zipCode = 'Hello World';// 應(yīng)該產(chǎn)生一個(gè)一個(gè)錯(cuò)誤因?yàn)閆IP碼是無效的 
  3. person.set('address', address); 
  4. console.log(person.get('address')); 
  5. /* 打印包含如下屬性的對(duì)象. 
  6.     'street': '1st Street' 
  7.     'city': 'Austin', 
  8.     'state': 'TX' 
  9.     'zipCode': 'Hello World' 
  10. */ 

為什么會(huì)這樣?我們的校驗(yàn)方法不是已經(jīng)返回一個(gè)錯(cuò)誤了嗎?!為什么attributes 屬性還是被改變了?原因正如前面所說,Backbone.js不會(huì)復(fù)制模型的attributes對(duì)象; 它僅僅返回你所請(qǐng)求的東西。所以,你可能會(huì)猜到,如果你請(qǐng)求的是一個(gè)對(duì)象(如上面的address),你會(huì)得到那個(gè)對(duì)象的引用,并且你對(duì)這個(gè)對(duì)象的所有修 改都會(huì)直接地操作在模型中的實(shí)際對(duì)象中(因此這樣的修改方式并不會(huì)導(dǎo)致校驗(yàn)失敗,因?yàn)閷?duì)象的引用并沒有改變)。這個(gè)問題很可能會(huì)導(dǎo)致你花費(fèi)幾小時(shí)來進(jìn)行調(diào) 試和診斷。

這個(gè)問題會(huì)逮住一些使用Backbone,js的新手甚至經(jīng)驗(yàn)豐富卻不夠警惕的JavaScript開發(fā)者。這個(gè)問題已經(jīng)在GitHub issues 的Backbone.js部分引起了大量的討論。像 Jeremy Ashkenas 所指出的,執(zhí)行深復(fù)制是一個(gè)非常棘手的問題,對(duì)那些有較大深度的對(duì)象來說,它將會(huì)是個(gè)非常昂貴的操作。

幸運(yùn)地,jQuery提供了一些深復(fù)制的實(shí)現(xiàn),$.extend。順帶說一句,Underscore.js,Backbone.js的一個(gè)依賴插件,也提供了類似的方法 _.extend ,但我會(huì)避免使用它,因?yàn)樗⒉粓?zhí)行深復(fù)制。

 
 
 
 
  1. var address = $.extend(true, {}, person.address); 

我們現(xiàn)在得到了 address 對(duì)象的一個(gè)精確的拷貝,因此我們可以隨心所欲地修改它的內(nèi)容而不用擔(dān)心修改到person中的address 對(duì)象。你應(yīng)該意識(shí)到此模式適用于上述那個(gè)例子僅因?yàn)閍ddress 對(duì)象的所有成員都是原始值(numbers, strings, 等等),所以當(dāng)深復(fù)制的對(duì)象中還包含有子對(duì)象時(shí)必須謹(jǐn)慎地使用。你應(yīng)該知道執(zhí)行一個(gè)對(duì)象的深復(fù)制會(huì)產(chǎn)生一個(gè)小的性能影響,但我從沒見過它導(dǎo)致了什么顯而易 見的問題。盡管這樣,如果你對(duì)一個(gè)復(fù)雜對(duì)象的執(zhí)行深復(fù)制或者一次性執(zhí)行上千個(gè)對(duì)象的深復(fù)制,你可能會(huì)想做一些性能分析。這正是下一個(gè)模式出現(xiàn)的原因。

#p#

為對(duì)象創(chuàng)建Facades

在真實(shí)的世界里,需求經(jīng)常會(huì)更改,所以那些通過模型和集合的查詢而從終端返回的JSON數(shù)據(jù)也會(huì)有所改變。如果你的視圖與底層數(shù)據(jù)模型緊緊地耦合,這將會(huì)讓你感到非常麻煩。因此,我為所有的對(duì)象創(chuàng)建了獲取器和設(shè)置器

很多人贊成這種模式。就是如果任何底層數(shù)據(jù)結(jié)構(gòu)被改變,視圖層不應(yīng)該更新太多;當(dāng)你只有一個(gè)數(shù)據(jù)入口的時(shí)候,你就不太可能忘記執(zhí)行深復(fù)制,并且你的代碼會(huì)變得更加可維護(hù)和調(diào)試。但帶來的負(fù)面影響是這種模式會(huì)讓你的模型和集合有點(diǎn)膨脹。

讓我們通過一個(gè)例子來搞清楚這個(gè)模式。假設(shè)我們有一個(gè)Hotel 模型,其中包含了rooms和當(dāng)前可用的rooms,我們希望能夠通過床位尺寸值來取得相應(yīng)的rooms。

 
 
 
 
  1. var Hotel = Backbone.Model.extend({ 
  2.     defaults: { 
  3.         "availableRooms": ["a"], 
  4.         "rooms": { 
  5.             "a": { 
  6.                 "size": 1200, 
  7.                 "bed": "queen" 
  8.             }, 
  9.             "b": { 
  10.                 "size": 900, 
  11.                 "bed": "twin" 
  12.             }, 
  13.             "c": { 
  14.                 "size": 1100, 
  15.                 "bed": "twin" 
  16.             } 
  17.         }, 
  18.  
  19.         getRooms: function() { 
  20.             $.extend(true, {}, this.get("rooms")); 
  21.         }, 
  22.  
  23.         getRoomsByBed: function(bed) { 
  24.             return _.where(this.getRooms(), { "bed": bed }); 
  25.         } 
  26.     } 
  27. }); 

讓我們假設(shè)明天你將會(huì)發(fā)布你的代碼,并且終端的開發(fā)者忘記告訴你rooms的數(shù)據(jù)結(jié)構(gòu)從Object變成了一個(gè)array。你的代碼現(xiàn)在如下所示:

 
 
 
 
  1. var Hotel = Backbone.Model.extend({ 
  2.     defaults: { 
  3.         "availableRooms": ["a"], 
  4.         "rooms": [ 
  5.             { 
  6.                 "name": "a", 
  7.                 "size": 1200, 
  8.                 "bed": "queen" 
  9.             }, 
  10.             { 
  11.                 "name": "b", 
  12.                 "size": 900, 
  13.                 "bed": "twin" 
  14.             }, 
  15.             { 
  16.                 "name": "c", 
  17.                 "size": 1100, 
  18.                 "bed": "twin" 
  19.             } 
  20.         ], 
  21.  
  22.         getRooms: function() { 
  23.             var rooms = $.extend(true, {}, this.get("rooms")), 
  24.              newRooms = {}; 
  25.  
  26.            // transform rooms from an array back into an object 
  27.             _.each(rooms, function(room) { 
  28.                 newRooms[room.name] = { 
  29.                     "size": room.size, 
  30.                     "bed": room.bed 
  31.                 } 
  32.             }); 
  33.         }, 
  34.  
  35.         getRoomsByBed: function(bed) { 
  36.             return _.where(this.getRooms(), { "bed": bed }); 
  37.         } 
  38.     } 
  39. }); 

為了將Hotel 轉(zhuǎn)換為應(yīng)用所期望的數(shù)據(jù)結(jié)構(gòu),我們僅僅更新了一個(gè)方法,這讓我們整個(gè)App的仍然正常工作。如果我們沒有創(chuàng)建一個(gè)rooms數(shù)據(jù)的獲取器,我們可能不得不 更新每一個(gè)rooms的數(shù)據(jù)入口。理想情況下,你為了使用一個(gè)新的數(shù)據(jù)結(jié)構(gòu)而會(huì)想要更新所有的接口方法。但如果由于時(shí)間緊迫而不得不盡快發(fā)布代碼的話,這 個(gè)模式能拯救你。

順帶提一下,這個(gè)模式既可以被認(rèn)為是一個(gè)facade 設(shè)計(jì)模式,因?yàn)樗[藏了對(duì)象復(fù)制的細(xì)節(jié),也可以被稱為 bridge 設(shè)計(jì)模式,因?yàn)樗梢员挥糜谵D(zhuǎn)換所期望的數(shù)據(jù)結(jié)構(gòu)。因而一個(gè)好的習(xí)慣是在所有的對(duì)象上使用獲取器和設(shè)置器。

存儲(chǔ)數(shù)據(jù)但不同步到服務(wù)器

盡管Backbone.js規(guī)定模型和集合會(huì)映射到REST-ful終端,但你有時(shí)候會(huì)發(fā)現(xiàn)你只是想將數(shù)據(jù)存儲(chǔ)在模型或者集合而不同步到服務(wù)器。一些其他關(guān)于Backbone.js的文章,像“Backbone.js Tips: Lessons From the Trenches”就講解過這個(gè)模式。讓我們快速地通過一個(gè)例子來看看什么時(shí)候這個(gè)模式會(huì)派上用場(chǎng)。假設(shè)你有個(gè)ul列表。

 
 
 
 
    •  
    •     
    • One
    •  
    •     
    • Two
    •  
    •     . . . 
    •     
    • n
    •  
     

當(dāng)n值為200并且用戶點(diǎn)擊了其中一個(gè)列表項(xiàng),那個(gè)列表項(xiàng)會(huì)被選中并添加了一個(gè)類以直觀地顯示。實(shí)現(xiàn)它的一個(gè)方法如下所示:

 
 
 
 
  1. var Model = Backbone.Model.extend({ 
  2.     defaults: { 
  3.         items: [ 
  4.             { 
  5.                 "name": "One", 
  6.                 "id": 1            
  7.             }, 
  8.             { 
  9.                 "name": "Two", 
  10.                 "id": 2            
  11.             }, 
  12.             { 
  13.                 "name": "Three", 
  14.                 "id": 3            
  15.             } 
  16.         ] 
  17.     } 
  18. }); 
  19.  
  20. var View = Backbone.View.extend({ 
  21.     template: _.template($('#list-template').html()), 
  22.  
  23.     events: { 
  24.         "#items li a": "setSelectedItem" 
  25.     }, 
  26.  
  27.     render: function() { 
  28.         $(this.el).html(this.template(this.model.toJSON())); 
  29.     }, 
  30.  
  31.     setSelectedItem: function(event) { 
  32.         var selectedItem = $(event.currentTarget); 
  33.        // Set all of the items to not have the selected class 
  34.         $('#items li a').removeClass('selected'); 
  35.         selectedItem.addClass('selected'); 
  36.         return false; 
  37.     } 
  38. }); 
  39.  
  40.  

現(xiàn)在我們想要知道哪一個(gè)item被選中。一個(gè)方法是遍歷整個(gè)列表。但如果這個(gè)列表過長,這會(huì)是一個(gè)昂貴的操作。因此,當(dāng)用戶點(diǎn)擊其中的列表項(xiàng)時(shí),我們應(yīng)該將它存儲(chǔ)起來。

 
 
 
 
  1. var Model = Backbone.Model.extend({ 
  2.     defaults: { 
  3.         selectedId: undefined, 
  4.         items: [ 
  5.             { 
  6.                 "name": "One", 
  7.                 "id": 1 
  8.             }, 
  9.             { 
  10.                 "name": "Two", 
  11.                 "id": 2 
  12.             }, 
  13.             { 
  14.                 "name": "Three", 
  15.                 "id": 3 
  16.             } 
  17.         ] 
  18.     } 
  19. }); 
  20.  
  21. var View = Backbone.View.extend({ 
  22.     initialize: function(options) { 
  23.        // Re-render when the model changes 
  24.         this.model.on('change:items', this.render, this); 
  25.     }, 
  26.  
  27.     template: _.template($('#list-template').html()), 
  28.  
  29.     events: { 
  30.         "#items li a": "setSelectedItem" 
  31.     }, 
  32.  
  33.     render: function() { 
  34.         $(this.el).html(this.template(this.model.toJSON())); 
  35.     }, 
  36.  
  37.     setSelectedItem: function(event) { 
  38.         var selectedItem = $(event.currentTarget); 
  39.        // Set all of the items to not have the selected class 
  40.         $('#items li a').removeClass('selected'); 
  41.         selectedItem.addClass('selected'); 
  42.        // Store a reference to what item was selected 
  43.         this.model.set('selectedId', selectedItem.data('id')); 
  44.         return false; 
  45.     } 
  46. }); 

現(xiàn)在我們能夠輕易地搜索我們的模型來確定哪一個(gè)item被選中,并且我們避免了遍歷文檔對(duì)象模型 (DOM)。這個(gè)模式對(duì)于存儲(chǔ)一些你想要跟蹤的外部數(shù)據(jù)非常有用;還要記住的是你能夠創(chuàng)建不需要與終端相關(guān)聯(lián)的模型和集合。

這個(gè)模式的消極影響是你的模型或集合并不是真正地采用RESTful 架構(gòu)因?yàn)樗鼈儧]有完美地映射到網(wǎng)絡(luò)資源。另外,這個(gè)模式會(huì)讓你的模型帶來一點(diǎn)兒膨脹;并且如果你的終端嚴(yán)格地只接收它所期望的JSON數(shù)據(jù),它會(huì)給你帶來一點(diǎn)兒麻煩。

#p#

渲染視圖的一部分而不是渲染整個(gè)視圖

當(dāng)你第一次開發(fā)Backbone.js應(yīng)用,你的視圖一般會(huì)是這樣的結(jié)構(gòu):

 
 
 
 
  1. var View = Backbone.View.extend({ 
  2.     initialize: function(options) { 
  3.         this.model.on('change', this.render, this); 
  4.     }, 
  5.  
  6.     template: _.template($(‘#template’).html()), 
  7.  
  8.     render: function() { 
  9.         this.$el.html(template(this.model.toJSON()); 
  10.         $(‘#a’, this.$el).html(this.model.get(‘a(chǎn)’)); 
  11.         $(‘#b’, this.$el).html(this.model.get(‘b’)); 
  12.     } 
  13. }); 

在這里,你的模型的任何改變都會(huì)觸發(fā)一次視圖的完整的重新渲染。當(dāng)我第一次使用Backbone.js來做開發(fā)的時(shí)候,我也使用過這種模式。但隨著我代碼的膨脹,我很快意識(shí)到這個(gè)方法是不可維護(hù)和不理想的,因?yàn)槟P偷娜魏螌傩缘母淖兌紩?huì)讓視圖完全重新渲染。

當(dāng)我遇到這個(gè)問題的時(shí)候,我馬上在Google搜索其他人是怎么做的并且找到了Ian Storm Taylor的博客寫的一篇文章, “Break Apart Your Backbone.js Render Methods,”,其中他提到了監(jiān)聽模型個(gè)別的屬性改變并且響應(yīng)的方法僅僅重新渲染視圖的一部分。Taylor也提到重渲染方法應(yīng)該返回自身的this對(duì)象,這樣那些單獨(dú)的重渲染方法就可以輕易地串聯(lián)起來。下面的這個(gè)例子已經(jīng)作出了修改而變得更易于維護(hù)和管理了,因?yàn)楫?dāng)模型屬性改變的時(shí)候我們僅僅更新相應(yīng)部分的視圖。

 
 
 
 
  1. var View = Backbone.View.extend({ 
  2.     initialize: function(options) { 
  3.         this.model.on('change:a', this.renderA, this); 
  4.         this.model.on('change:b', this.renderB, this); 
  5.     }, 
  6.  
  7.     renderA: function() { 
  8.         $(‘#a’, this.$el).html(this.model.get(‘a(chǎn)’)); 
  9.         return this; 
  10.     }, 
  11.  
  12.     renderB: function() { 
  13.         $(‘#b’, this.$el).html(this.model.get(‘b’)); 
  14.         return this; 
  15.     }, 
  16.  
  17.     render: function() { 
  18.         this 
  19.             .renderA() 
  20.             .renderB(); 
  21.     } 
  22. }); 

還要提到的是,許多插件,像 Backbone.StickIt 和 Backbone.ModelBinder,提供了視圖元素和模型屬性之間的鍵值綁定,這能夠節(jié)省你很多的相似代碼。因此,如果你有很多復(fù)雜的表單字段,可以試著使用它們。

保持模型和視圖分離

像Jeremy Ashkenas 在Backbone.js的 GitHub issues指出的一個(gè)問題,除了模型不能夠由它們的視圖來創(chuàng)建以外,Backbone.js并不在數(shù)據(jù)層和視圖層之間實(shí)施任何真正的關(guān)注點(diǎn)分離。你覺得應(yīng)該在數(shù)據(jù)層和視圖層之間實(shí)施關(guān)注點(diǎn)分離嗎?我和其他的一些Backbone.js開發(fā)者,像Oz Katz和 Dayal,都認(rèn)為這個(gè)答案毫無疑問應(yīng)該是要的:模型和集合,代表著數(shù)據(jù)層,應(yīng)該禁止任何綁定到它們的視圖的入口,從而保持一個(gè)完全的關(guān)注點(diǎn)分離。如果你不遵循這個(gè)關(guān)注點(diǎn)分離,你的代碼很快就會(huì)變得像意大利面條那樣糾纏不清,而沒有人會(huì)喜歡這種代碼。

保持你的數(shù)據(jù)層和視圖層完全地分離可以使你擁有更加地模塊化,可重用和可維護(hù)的代碼。你能夠輕易地在你的應(yīng)用中重用和拓展模型和集合而不需要擔(dān)心和他們綁定的視圖。遵循這個(gè)模式能讓新加入項(xiàng)目的開發(fā)者快速的投入到代碼中。因?yàn)樗鼈兙_的知道哪里會(huì)發(fā)生視圖的渲染以及哪里存放著應(yīng)用的業(yè)務(wù)邏輯。

這個(gè)模式也強(qiáng)制使用了單一責(zé)任原則,該原則規(guī)定了每一個(gè)類應(yīng)該只有一個(gè)單獨(dú)的責(zé)任,并且它的職責(zé)應(yīng)該封裝在這個(gè)類中,因?yàn)槟愕哪P秃图蠎?yīng)該只負(fù)責(zé)處理數(shù)據(jù),視圖應(yīng)該只負(fù)責(zé)處理渲染。

路由器中的參數(shù)映射

使用例子是展示這個(gè)模式如何產(chǎn)生的最好方法。例如:有一些搜索頁面,它們?cè)试S用戶添加兩個(gè)不同的過濾類型,foo 和bar,每一個(gè)都附有大量的選項(xiàng)。因此,你的URL結(jié)構(gòu)看起來將會(huì)像這樣:

 
 
 
 
  1. 'search/:foo' 
  2. 'search/:bar' 
  3. 'search/:foo/:bar' 

現(xiàn)在,所有的路由使用一個(gè)確切的視圖和模型,所以,理想狀況下,你會(huì)樂意它們都用同一個(gè)方法,search()。但是,如果你檢查 Backbone.js,會(huì)發(fā)現(xiàn)沒有任何形式的參數(shù)映射;這些參數(shù)只是簡單地從左到右扔到方法里面去。所以,為了讓它們都能使用相同的方法,你最終要?jiǎng)?chuàng)建 不同的方法來正確地映射參數(shù)到search()方法。

 
 
 
 
  1. routes: { 
  2.     'search/:foo': 'searchFoo', 
  3.     'search/:bar': 'searchBar', 
  4.     'search/:foo/:bar': 'search' 
  5. }, 
  6.  
  7. search: function(foo, bar) {     
  8. }, 
  9. // I know this function will actually still map correctly, but for explanatory purposes, it's left in. 
  10. searchFoo: function(foo) { 
  11.     this.search(foo, undefined); 
  12. }, 
  13.  
  14. searchBar: function(bar) { 
  15.     this.search(undefined, bar); 
  16. }, 

和你想的一樣,這種模式會(huì)快速地膨脹你的路由。當(dāng)我第一次使用接觸這種模式的時(shí)候,我嘗試使用正則表達(dá)式在實(shí)際方法定義中做一些解析而“神奇地”映 射這些參數(shù),但這只能在參數(shù)容易區(qū)分的情況下起作用。所以我放棄了這個(gè)方法(我有時(shí)候依然會(huì)在Backbone插件中使用它)。我在issue on GitHub上提出過這個(gè)問題,Ashkenas 給我的建議是在search方法中映射所有的參數(shù)。

下面這段代碼已經(jīng)變得更加具備可維護(hù)性:

 
 
 
 
  1. routes: { 
  2.     'base/:foo': 'search', 
  3.     'base/:bar': 'search', 
  4.     'base/:foo/:bar': 'search' 
  5. }, 
  6.  
  7. search: function() { 
  8.     var foo, bar, i; 
  9.  
  10.     for(i = arguments.length - 1; i >= 0; i--) { 
  11.  
  12.         if(arguments[i] === 'something to determine foo') { 
  13.             foo = arguments[i]; 
  14.             continue; 
  15.         } 
  16.         else if(arguments[i] === 'something to determine bar') { 
  17.             bar = arguments[i]; 
  18.             continue; 
  19.         } 
  20.     } 
  21. }, 

這個(gè)模式可以徹底地減少路由器的膨脹。然而,要意識(shí)到它對(duì)于不可識(shí)別的參數(shù)時(shí)無效的。舉個(gè)例子,如果你有兩個(gè)傳遞ID的參數(shù)并且都它們以 XXXX-XXXX 這種模式表現(xiàn),你將無法確定哪一個(gè)ID對(duì)應(yīng)的是哪一個(gè)參數(shù)。

model.fetch() 不會(huì)清除你的模型

這個(gè)問題通常會(huì)絆倒使用Backbone.js的新手: model.fetch() 并不會(huì)清理你的模型,而是會(huì)將取回來的數(shù)據(jù)合并到你的模型當(dāng)中。因此,如果你當(dāng)前的模型有x,,y 和 z 屬性并且你通過fetch得到了一個(gè)新的 y 和z 值,接下來 x 會(huì)保持模型原來的值,僅僅 y 和z 的值會(huì)得到更新,下面這個(gè)例子直觀地說明了這個(gè)概念。

 
 
 
 
  1. var Model = Backbone.Model.extend({ 
  2.     defaults: { 
  3.         x: 1, 
  4.         y: 1, 
  5.         z: 1 
  6.     } 
  7. }); 
  8. var model = new Model(); 
  9. /* model.attributes yields 
  10.     x: 1, 
  11.     y: 1, 
  12.     z: 1 
  13. } */ 
  14. model.fetch(); 
  15. /* let’s assume that the endpoint returns this 
  16.     y: 2, 
  17.     z: 2, 
  18. } */ 
  19. /* model.attributes now yields 
  20.     x: 1, 
  21.     y: 2, 
  22.     z: 2 
  23. } */ 

#p#

PUT請(qǐng)求需要一個(gè)ID屬性

這個(gè)問題也只通常出現(xiàn)在Backbone.js的新手中。當(dāng)你調(diào)用.save() 方法時(shí),你會(huì)發(fā)送一個(gè)HTTP PUT 請(qǐng)求,要求你的模型已經(jīng)設(shè)置了一個(gè)ID屬性。HTTP PUT 是被設(shè)計(jì)為一個(gè)更新動(dòng)作的,所以發(fā)送PUT請(qǐng)求的時(shí)候要求你的模型已有一個(gè)ID屬性是合情理的。在理想的世界里,你的所有模型都會(huì)有一個(gè)名為id的屬性, 但現(xiàn)實(shí)情況是,你從終端接收的JSON數(shù)據(jù)的ID屬性并不總是會(huì)剛好命名為id。

因此,如果你需要更新你的模型,請(qǐng)確定在保存前你的模型具有一個(gè)ID。當(dāng)終端返回的ID屬性變量名不為 id 的時(shí)候,0.5及以上的版本的Backbone.js允許你使用 idAttribute 來改變ID屬性的名字。

如果使用的Backbone.js的版本仍低于0.5,我建議你修改集合或模型中的 parse 方法來映射期望的ID屬性到真正的ID屬性。這里有一個(gè)讓你快速掌握這個(gè)技巧的例子,讓我們假設(shè)你有一個(gè)cars集合,它的ID屬性名為carID .

 
 
 
 
  1. parse: function(response) { 
  2.  
  3.     _.each(response.cars, function(car, i) { 
  4.        // map the returned ID of carID to the correct attribute ID 
  5.         response.cars[i].id = response.cars[i].carID; 
  6.     }); 
  7.  
  8.     return response; 
  9. }, 

頁面加載中的模型數(shù)據(jù)

一些時(shí)候你會(huì)發(fā)現(xiàn)你需要在頁面加載的時(shí)候就使用數(shù)據(jù)來初始化你的集合和模型。一些關(guān)于Backbone.js模式的文章,像Rico Sta Cruz的“Backbone Patterns”和Katz的“Avoiding Common Backbone.js Pitfalls,”談?wù)摰搅诉@個(gè)模式。使用你選擇的服務(wù)端語言,通過嵌入代碼到頁面并將數(shù)據(jù)放在單個(gè)模型的屬性或JSON當(dāng)中,你能夠輕易地實(shí)現(xiàn)這個(gè)模式。舉個(gè)例子,在Rails中,我會(huì)這樣使用:

 
 
 
 
  1. // a single attribute 
  2. var model = new Model({ 
  3.     hello: <%= @world %> 
  4. });// or to have json 
  5. var model = new Model(<%= @hello_world.to_json %>); 

使用這個(gè)模式能夠通過“馬上渲染你的頁面”來提高你的搜索引擎排名,并且它能通過限制應(yīng)用的HTTP請(qǐng)求來徹底地縮短你的應(yīng)用啟動(dòng)和運(yùn)行所花費(fèi)的時(shí)間。

處理驗(yàn)證失敗的模型屬性

你經(jīng)常會(huì)想知道哪一個(gè)模型屬性的驗(yàn)證失敗了。舉個(gè)例子,如果你有一個(gè)極度復(fù)雜的表單域,你可能想知道哪一個(gè)模型屬性驗(yàn)證失敗,這樣你能夠高亮顯示相 應(yīng)的表單域。不幸的是,提醒你的視圖哪一個(gè)模型屬性驗(yàn)證失敗并沒有直接在Backbone.js中實(shí)現(xiàn),但你可以使用不同的模式來處理這個(gè)問題。

返回一個(gè)錯(cuò)誤對(duì)象

通知你的視圖哪一個(gè)模型屬性驗(yàn)證失敗的一個(gè)模式是回傳一個(gè)帶有某種標(biāo)志的對(duì)象,該對(duì)象中詳述哪一個(gè)模型屬性驗(yàn)證失敗,就像下面這樣:

 
 
 
 
  1. // Inside your model 
  2. validate: function(attrs) { 
  3.     var errors = []; 
  4.  
  5.     if(attrs.a < 0) { 
  6.         errors.push({ 
  7.             'message': 'Form field a is messed up!', 
  8.             'class': 'a' 
  9.         }); 
  10.     } 
  11.     if(attrs.b < 0) { 
  12.         errors.push({ 
  13.             'message': 'Form field b is messed up!', 
  14.             'class': 'b' 
  15.         }); 
  16.     } 
  17.  
  18.     if(errors.length) { 
  19.         return errors; 
  20.     } 
  21. }// Inside your view 
  22. this.model.on('invalid’, function(model, errors) { 
  23.     _.each(errors, function(error, i) { 
  24.         $(‘.’ + error.class).addClass('error'); 
  25.         alert(error.message); 
  26.     }); 
  27. }); 

這個(gè)模式的優(yōu)點(diǎn)是你在一個(gè)位置處理了所有的無效信息。缺點(diǎn)是如果你處理不同的無效屬性,你的屬性校驗(yàn)部分會(huì)變?yōu)橐粋€(gè)比較大的 switch 或 if 語句。

廣播傳統(tǒng)錯(cuò)誤事件

由我朋友Derick Bailey建議的一個(gè)替換的模式,是對(duì)個(gè)別的模型屬性觸發(fā)自定義錯(cuò)誤事件。這能讓你的視圖為個(gè)別的屬性綁定指定的錯(cuò)誤事件。

 
 
 
 
  1. // Inside your model 
  2. validate: function(attrs) { 
  3.  
  4.     if(attrs.a < 0) { 
  5.             this.trigger(‘invalid:a’, 'Form field a is messed up!', this); 
  6.     } 
  7.     if(attrs.b < 0) { 
  8.             this.trigger(‘invalid:b’, 'Form field b is messed up!', this); 
  9.     } 
  10. }// Inside your view 
  11. this.model.on('invalid:a’, function(error) { 
  12.         $(‘a(chǎn)’).addClass('error'); 
  13.         alert(error); 
  14. }); 
  15. this.model.on('invalid:b’, function(error) { 
  16.         $(‘b’).addClass('error'); 
  17.         alert(error); 
  18. }); 

這個(gè)模式的優(yōu)點(diǎn)是你的視圖綁定了明確類型的錯(cuò)誤事件,并且如果你對(duì)每一類型的屬性錯(cuò)誤有明確的執(zhí)行指令,它能整頓你視圖代碼并使它更加可維護(hù)。這個(gè)模式的一個(gè)缺點(diǎn)是如果存在太多不同的想要處理的屬性錯(cuò)誤,你的視圖代碼會(huì)變得更加臃腫。

兩個(gè)模式都有他們的優(yōu)缺點(diǎn),所以在你應(yīng)該考慮哪一種模式更加適合你的用例。如果你想對(duì)所有的驗(yàn)證失敗處理都采用一個(gè)方法,那第一個(gè)方法會(huì)是個(gè)好選擇;如果你的每一個(gè)模型屬性都有明確的UI改變,那選第二個(gè)方法會(huì)更好。

HTTP狀態(tài)碼200觸發(fā)錯(cuò)誤

如果你的模型或集合訪問的終端返回了無效的JSON數(shù)據(jù),它們會(huì)觸發(fā)一個(gè)“error”事件,即使你的終端返回的HTTP狀態(tài)碼是200。這個(gè)情況通常出現(xiàn)在根據(jù)模擬JSON數(shù)據(jù)來做本地開發(fā)的時(shí)候。所以一個(gè)好方法是把你正在開發(fā)中的所有的模擬JSON文件都扔到JSON 驗(yàn)證器中檢驗(yàn)?;蛘邽槟愕腎DE安裝一個(gè)插件可以捕捉任何格式錯(cuò)誤的JSON。

創(chuàng)建一個(gè)通用的錯(cuò)誤展示

創(chuàng)建一個(gè)通用的錯(cuò)誤展示意味著你有一個(gè)統(tǒng)一的模式來處理和顯示錯(cuò)誤信息,這能夠節(jié)省你的時(shí)間,并能提升用戶的整體體驗(yàn)。在我開發(fā)的任何的Backbone.js 應(yīng)用中我都創(chuàng)建了一個(gè)通用的視圖來處理警告。

 
 
 
 
  1. var AlertView = Backbone.View.extend({ 
  2.     set: function(typeOfError, message) { 
  3.         var alert = $(‘.in-page-alert’).length ? $(‘.in-page-alert’): $(‘.body-alert’); 
  4.         alert 
  5.             .removeClass(‘error success warning’) 
  6.             .html(message) 
  7.             .fadeIn() 
  8.             .delay(5000) 
  9.      &n
    網(wǎng)站欄目:Backbone.js的技巧和模式
    網(wǎng)頁URL:http://m.5511xx.com/article/cdojesi.html