backbone.js的使用報(bào)告

一、準(zhǔn)備階段

1.1 框架選型

隨著對(duì)MV*架構(gòu)模式的逐步理解,越來(lái)越發(fā)覺(jué)對(duì)于一般的業(yè)務(wù)場(chǎng)景,mvvm是前端架構(gòu)的不二選擇。在我所了解的框架范圍內(nèi),與mvvm架構(gòu)模式最貼合的框架只有angular,無(wú)論是雙向數(shù)據(jù)綁定、指令,還有強(qiáng)化的html標(biāo)簽,angular提出的很多新概念都像是為mvvm理論量身定做的一套外衣。很可惜angular對(duì)ie8的支持不太友好,兼容ie8的angular插件也非常稀缺,對(duì)于國(guó)內(nèi)環(huán)境,ie8仍然占有較大的市場(chǎng)份額,無(wú)奈之下只能轉(zhuǎn)向輕量級(jí)的backbone。

1.2 官方文檔vs電子書(shū)

通過(guò)閱讀backbone的官網(wǎng)簡(jiǎn)介,總結(jié)下backbone特點(diǎn)(并非優(yōu)點(diǎn)):

  • 提供了基本的MVC結(jié)構(gòu),可以做到業(yè)務(wù)邏輯與視圖的分離(MV*框架最基本的功能)
  • 內(nèi)置支持restful風(fēng)格的API(做過(guò)項(xiàng)目后會(huì)發(fā)覺(jué),內(nèi)置的那套基本沒(méi)什么用,自定義會(huì)更合適)
  • 路由的支持(大部分MV*框架也都支持,也不是亮點(diǎn))
  • 方便與第三方插件集成(因?yàn)閎ackbone太輕量了,對(duì)于插件沒(méi)什么要求,這勉強(qiáng)可以算優(yōu)點(diǎn))
  • 兼容ie8(對(duì)比其他MV*框架,感覺(jué)這是唯一的優(yōu)點(diǎn),也是選擇它的理由)
  • 粗粒度的單向數(shù)據(jù)綁定(缺點(diǎn),每次更新視圖,都只能全部更新,當(dāng)然你可以自己寫(xiě)局部更新,會(huì)比較繁瑣)
  • 太輕量了(缺點(diǎn),連angular這種重量級(jí)的框架寫(xiě)法都會(huì)五花八門(mén),backbone這種就更別提了,新手根本無(wú)法駕馭它寫(xiě)出優(yōu)良的代碼)

由于backbone功能單薄,無(wú)法形成固有的mvc或是mvp模式,但是為了讓它變得好用,我們可以嘗試增強(qiáng)它的功能,讓它更接近我們想要的mvvm框架。mvvm框架最大特點(diǎn)是:雙向數(shù)據(jù)綁定,于是通過(guò)google:backbone data binding,找到了以下幾個(gè)backbone插件:Backbone.ModelBinder、Rivets.js、Backbone.Stickit。通過(guò)測(cè)試發(fā)現(xiàn)Rivets.js很好用,可惜不兼容ie8,ModelBinder配置不夠靈活,于是Stickit成為最佳選擇。

關(guān)于框架的學(xué)習(xí),我的思路是這樣的:官方文檔是一定要看的,但是沒(méi)必要從頭看到尾,官方開(kāi)頭那部分介紹是一定要看的,那里會(huì)告訴你框架是什么樣的,有什么特性,而具體的API只要看能反應(yīng)出框架特性的那幾個(gè)API就夠了,其他的都是用來(lái)查的。有些API不用查,你也知道它肯定有,就像你學(xué)完java后學(xué)C++,你知道C++里肯定有for循環(huán)。
<b>只看官網(wǎng)文檔是遠(yuǎn)遠(yuǎn)不夠的,文檔只是告訴你可以這樣用,但是沒(méi)有告訴你該不該這樣用,所以當(dāng)你大體了解了一個(gè)框架的基礎(chǔ)知識(shí)后,應(yīng)該找一本名叫《xxx框架最佳實(shí)踐》的電子書(shū),了解下怎么用才合理,對(duì)于輕量級(jí)的框架尤其如此。</b>

學(xué)計(jì)算機(jī)知識(shí),一個(gè)wiki百科就夠了(要翻墻),千萬(wàn)不要看國(guó)內(nèi)某百科,連自己貼吧的內(nèi)容都可以當(dāng)參考文獻(xiàn),實(shí)在是太不靠譜了。

二、實(shí)踐階段

準(zhǔn)備階段做得越多,實(shí)踐起來(lái)就越輕松,項(xiàng)目需求分析階段,開(kāi)發(fā)人員的時(shí)間如果用來(lái)做技術(shù)調(diào)研、框架選型、編寫(xiě)demo、測(cè)試性能、編寫(xiě)非業(yè)務(wù)組件等工作,時(shí)間還是會(huì)比較緊張的。總結(jié)了一下項(xiàng)目中的問(wèn)題及解決方案:

2.1 如何編寫(xiě)model層代碼

對(duì)于mvc新手,經(jīng)常會(huì)誤解m的含義,認(rèn)為m只是表示數(shù)據(jù)。實(shí)際上mvc是按照職責(zé)來(lái)劃分的,而非數(shù)據(jù)類(lèi)型。m表示業(yè)務(wù)層,即包含表示業(yè)務(wù)邏輯的數(shù)據(jù)模型,同時(shí)也包含操作這些數(shù)據(jù)的方法。反應(yīng)到backbone項(xiàng)目中,m層的寫(xiě)法如下:

var Product = Backbone.Model.extend({

    // 業(yè)務(wù)數(shù)據(jù)模型
    defaults: {
        name: “”,
        price: 0
    },
    
    // 操作數(shù)據(jù)的方法
    create: function() {...},
    remove: function() {...},
    modify: function() {...},
    query: function() {...}
});

不要在view中直接調(diào)用沒(méi)有業(yè)務(wù)含義的底層方法:fetch、save等,這將導(dǎo)致model與view耦合在一起,view層的代碼變得繁雜且難以維護(hù)。

2.2 事件與邏輯分離

backbone提供了View類(lèi),很多人并沒(méi)有意識(shí)到事件與邏輯的解耦,他們通常這樣寫(xiě):

var ProductView = Backbone.View.extend({

    // 注冊(cè)事件
    events: {
        "click #saveBtn": "create",
        ....
    },
    
    // 創(chuàng)建
    create: function() {

        // 針對(duì)click準(zhǔn)備一些數(shù)據(jù),可能涉及到dom操作
        var data = ....;
        
        // 執(zhí)行創(chuàng)建的邏輯
        ...
    }
});

當(dāng)觸發(fā)創(chuàng)建邏輯的事件不止一個(gè)時(shí),會(huì)變成這樣:

var ProductView = Backbone.View.extend({

    // 注冊(cè)事件
    events: {
        "click #saveBtn": "createForClick",
        "blur #xxInput": "createForBlur",
        ....
    },
    
    // 創(chuàng)建for click
    createForClick: function() {

        // 針對(duì)click準(zhǔn)備一些數(shù)據(jù),可能涉及到dom操作
        var data = ....;
        
        // 執(zhí)行創(chuàng)建的邏輯
        ...
    },

    // 創(chuàng)建for blur
    createForBlur: function() {

        // 針對(duì)blur準(zhǔn)備一些數(shù)據(jù),可能涉及到dom操作
        var data = ....;
        
        // 執(zhí)行創(chuàng)建的邏輯
        ...
    }
});

此時(shí)你會(huì)發(fā)現(xiàn)處理邏輯的代碼重復(fù)了,所以將事件與邏輯分離的一個(gè)優(yōu)點(diǎn)是:邏輯代碼可以復(fù)用,正確的寫(xiě)法如下:

var ProductView = Backbone.View.extend({

    // 注冊(cè)事件
    events: {
        "click #saveBtn": "createForClick",
        "blur #xxInput": "createForBlur",
        ....
    },
    
    // 響應(yīng)click事件的創(chuàng)建
    createForClick: function() {

        // 針對(duì)click準(zhǔn)備一些數(shù)據(jù),可能涉及到dom操作
        var data = ....;
        
        // 執(zhí)行創(chuàng)建的邏輯
        this.create(data);
    },

    // 響應(yīng)blur事件的創(chuàng)建
    createForBlur: function() {

        // 針對(duì)blur準(zhǔn)備一些數(shù)據(jù),可能涉及到dom操作
        var data = ....;
        
        // 執(zhí)行創(chuàng)建的邏輯
        this.create(data);
    },

    // 執(zhí)行創(chuàng)建
    create: function(data) {...}
});

事件與邏輯的分離最大的好處是可以方便的進(jìn)行單元測(cè)試,以上面為例,只需針對(duì)create方法進(jìn)行測(cè)試,就能驗(yàn)證邏輯的正確性,而非邏輯的dom操作是不在單元測(cè)試范圍之內(nèi)的。

2.3 凈化路由代碼

backbone提供了路由功能,可以方便的根據(jù)網(wǎng)址跳轉(zhuǎn)到指定的視圖,很多人的寫(xiě)法是這樣的:

var AppRouter = Backbone.Router.extend({
    "route1": "createView1",
    "route2": "createView2",
    ....,

    createView1: function() {
        // 1.操作model層方法,獲取視圖所需數(shù)據(jù)
        ...
        // 2.new一個(gè)視圖對(duì)象,傳遞數(shù)據(jù)到視圖中
        ...
        // 3.其他的邏輯
        ...
    },

    createView2: function() {
        // 1.操作model層方法,獲取視圖所需數(shù)據(jù)
        ...
        // 2.new一個(gè)視圖對(duì)象,傳遞數(shù)據(jù)到視圖中
        ...
        // 3.其他的邏輯
        ...
    }
});

隨著需求的增加,創(chuàng)建視圖的邏輯會(huì)變的越來(lái)越復(fù)雜,整個(gè)路由的代碼會(huì)顯得非常臃腫,還有一個(gè)問(wèn)題,不單單路由里需要?jiǎng)?chuàng)建視圖,其他的地方也會(huì)用到,這個(gè)時(shí)候,重復(fù)的代碼又出現(xiàn)了。解決這個(gè)問(wèn)題的方案是抽取出創(chuàng)建視圖的邏輯,實(shí)際項(xiàng)目中我抽取了一個(gè)文件夾叫作:controllers,里面以業(yè)務(wù)功能為單位,存放創(chuàng)建視圖邏輯的js文件,比如處理產(chǎn)品的controller,可以定義為productCtrl.js,代碼如下:

var productCtrl= (function() {
    var create = function() {
        // 1.操作model層方法,獲取視圖所需數(shù)據(jù)
        ...
        // 2.new一個(gè)視圖對(duì)象,傳遞數(shù)據(jù)到視圖中
        ...
        // 3.其他的邏輯
        ...
    };

    return {
        create: create
    };
});

此時(shí)路由的代碼就變得非常清爽了,同時(shí)其他地方需要?jiǎng)?chuàng)建視圖時(shí),只需要調(diào)用productCtrl.create()即可,路由代碼:

var AppRouter = Backbone.Router.extend({
    "route1": "createView1",
    "route2": "createView2",
    ....,

    createView1: function() {
        productCtrl.create();
    },

    createView2: function() {
        ...
    }
});
2.4 引入bower-installer優(yōu)化bower文件結(jié)構(gòu)

前端構(gòu)建時(shí)需要合并第三方的js、css文件,但是每個(gè)插件的目錄結(jié)構(gòu)不盡相同,導(dǎo)致grunt命令寫(xiě)起來(lái)非常繁瑣,為了盡量統(tǒng)一處理,引入了bower-installer插件,主要目的是抽取出插件的核心文件,將其放入規(guī)則統(tǒng)一的目錄中,方便進(jìn)一步處理。 bower-installer的github地址:https://github.com/blittle/bower-installer

2.4.1 bower-installer使用
  • 安裝:npm install -g bower-installer
  • 運(yùn)行:bower-installer
    具體配置參考github上的文檔
2.4.2 基于bower-installer引入第三方插件的流程(以jquery為例)
  1. 配置bower.json文件:"jquery": "1.11.3"
  2. 執(zhí)行bower install下載jquery插件
  3. 執(zhí)行bower installer抽取jquery核心文件到bower_main_files目錄
  4. 引入文件:在index.html中引入插件的根目錄由bower_components改為bower_main_files
2.5 mvvm的缺陷

開(kāi)發(fā)過(guò)程一切都很順利,只踩到兩個(gè)坑:<b>性能</b>、<b>復(fù)雜界面的邏輯處理</b>,而這兩個(gè)坑是由mvvm的基因決定的。

mvvm的雙向數(shù)據(jù)綁定可以讓開(kāi)發(fā)變得非常便利,但同時(shí)也帶來(lái)了兩個(gè)問(wèn)題:

  • 為了將model與dom中的元素一一對(duì)應(yīng)進(jìn)行綁定,即便最簡(jiǎn)單的界面,也會(huì)消耗大量性能,當(dāng)需要一次性加載大量數(shù)據(jù)時(shí),性能問(wèn)題就會(huì)凸顯。
  • 數(shù)據(jù)綁定是基于觀察者模式構(gòu)建的,當(dāng)界面中存在多個(gè)組件,且組件間有復(fù)雜交互時(shí),代碼很難跟蹤,調(diào)試會(huì)變得非常困難,當(dāng)修改了某個(gè)model時(shí),你無(wú)法清晰的了解后面會(huì)發(fā)生什么。

針對(duì)mvvm的缺點(diǎn),以下業(yè)務(wù)場(chǎng)景是不適合的:

  1. 由于極端的用戶(hù)體驗(yàn)要求,需要一次性渲染大量數(shù)據(jù),不能分頁(yè)的場(chǎng)景。
  2. 組件多且交互過(guò)復(fù)雜的場(chǎng)景。

據(jù)說(shuō)angular2.0也傾向單向數(shù)據(jù)流,估計(jì)也是考慮到這個(gè)原因,react+flux也推崇單向數(shù)據(jù)流,也許這是一種趨勢(shì)。但對(duì)于一般的業(yè)務(wù)場(chǎng)景來(lái)說(shuō),雙向數(shù)據(jù)綁定還是非常實(shí)用的,所以具體采用什么方案還是要結(jié)合具體的業(yè)務(wù)場(chǎng)景。

三、總結(jié)

  • backbone.js是一個(gè)功能單薄的框架,它需要其他插件的輔助才能變得好用。
  • 沒(méi)有了解過(guò)xxx最佳實(shí)踐,就不要輕易在項(xiàng)目里使用,不然往往會(huì)得到xxx不好用的錯(cuò)誤結(jié)論。
  • 沒(méi)有一個(gè)模式永遠(yuǎn)是最佳的,只有適合業(yè)務(wù)場(chǎng)景的模式才是最佳模式。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,661評(píng)論 25 708
  • 彼岸花開(kāi)開(kāi)彼岸
    柒染韻墨閱讀 263評(píng)論 0 0
  • 魚(yú)游在水里 有了魚(yú)水之情 魚(yú)游進(jìn)了巖石之腹 再也不曾離開(kāi) 這是幸運(yùn) 還是緣分 愛(ài)上一個(gè)人 因?yàn)樯羁?所以永恒
    足下阿蒙閱讀 98評(píng)論 0 0
  • 大過(guò)年的人家都是寫(xiě)要好好過(guò)年,新年有什么好計(jì)劃等等之類(lèi)的,為什么我要寫(xiě)什么難的糊涂呢,好像這個(gè)詞不該過(guò)年時(shí)候說(shuō),或...
    才少說(shuō)閱讀 112評(píng)論 0 0
  • 背景:1. 本地windows系統(tǒng)已有開(kāi)發(fā)指定版本的jdk安裝包,已有tomcat解壓縮后的程序文件。無(wú)需另外下載...
    Joey_GZ閱讀 649評(píng)論 1 2