摘要:事件關(guān)于路由觸發(fā)事件是通過(guò)兩個(gè)函數(shù)來(lái)完成的,它們分別是和前者會(huì)檢測(cè)路由是否發(fā)生了改變,如果改變了就會(huì)觸發(fā)函數(shù)并調(diào)用函數(shù),而后者會(huì)通過(guò)路由片段來(lái)找到相關(guān)的事件函數(shù)來(lái)觸發(fā)。
注意:強(qiáng)烈建議一邊閱讀源碼一邊閱讀本文。
終于到了backbone源碼解讀的最后一篇,這一篇和前面幾篇時(shí)間上有一定的間隔(因?yàn)橐貙W(xué)校有一堆亂七八糟的事...)。在這一篇里面會(huì)講解Bakcbone的sync & router & histrory。sync比較簡(jiǎn)單,但是路由的部分就比較復(fù)雜了。個(gè)人覺(jué)得是整個(gè)backbone源碼里面最不好懂的一個(gè)部分,這個(gè)部分也使得backbone可以方便實(shí)現(xiàn)可以“返回”的單頁(yè)面應(yīng)用。個(gè)人覺(jué)得這個(gè)部分其實(shí)并沒(méi)有很MVC有很密切的關(guān)系,但是它非常重要。讀過(guò)源碼就會(huì)發(fā)現(xiàn),其實(shí)這一個(gè)部分與其他的模塊(Model,Collection & View)相對(duì)獨(dú)立。如果不希望使用backbone但希望能用到這個(gè)路由系統(tǒng)的話估計(jì)拆出來(lái)難度也不會(huì)很大。
總體來(lái)說(shuō)路由模塊由Router和Histrory組成,而Router事實(shí)上可以看成是對(duì)History的一個(gè)封裝。用戶直接操作的部分時(shí)Router,相關(guān)函數(shù)的處理(路由匹配時(shí)調(diào)用的函數(shù))也是在Router中完成。History主要是處理一個(gè)更加棘手的問(wèn)題,就是有關(guān)鏈接的問(wèn)題。這里面有關(guān)于跨瀏覽器的解決方案是非常值得學(xué)習(xí)的。
1. RouterRouter是對(duì)History的封裝,也是給用戶定義路由的接口。一般來(lái)說(shuō),用戶在使用Router的時(shí)候會(huì)定義一個(gè)routers的對(duì)象,里面是想關(guān)路由與處理函數(shù)組成的key-value。Router代碼中主要做兩件事,一件是對(duì)正則表達(dá)式的操作(可以看見(jiàn)里面很多令人痛苦的正則表達(dá)式),另一件事就是事件相關(guān)的綁定了。Router的相關(guān)代碼不多,寫(xiě)得比較精簡(jiǎn)。
1.1 函數(shù)綁定與執(zhí)行Router里面定義了兩種方法來(lái)定義路由事件,一個(gè)方法是用戶定義routers,通過(guò)初始化調(diào)用_bindRoutes函數(shù);一個(gè)方法是用自帶的route函數(shù)。其實(shí)兩個(gè)方法本質(zhì)上都是調(diào)用了route函數(shù),_bindRoutes里面實(shí)際上也是通過(guò)循環(huán)來(lái)調(diào)用route函數(shù)。因此路由函數(shù)重點(diǎn)在于route函數(shù)。
在route函數(shù)里面,一開(kāi)始是進(jìn)行一些參數(shù)的整理。然后就是調(diào)用了History模塊的route函數(shù),把正則(匹配參數(shù)用的)和一個(gè)回調(diào)函數(shù)傳了進(jìn)去。在回調(diào)函數(shù)里面就是做 執(zhí)行函數(shù)——觸發(fā)router的事件——觸發(fā)history的事件這幾個(gè)步驟,在History的route函數(shù)里面,只是簡(jiǎn)單的插入地把key和callback組成對(duì)象插入handlers數(shù)組里面而已。
1.2. 正則表達(dá)式轉(zhuǎn)化與使用Router函數(shù)里面最難懂也非常重要的部分是格式的轉(zhuǎn)換。在Router里面有兩個(gè)重要的函數(shù)_routeToRegExp函數(shù)和_extractParameters兩個(gè),這兩個(gè)函數(shù)與正則密切相關(guān)。
_extractParameters函數(shù)的作用是利用正則表達(dá)式,把傳進(jìn)來(lái)的url片段fragment分割成片段存進(jìn)數(shù)組當(dāng)中。這些片段是真實(shí)的已經(jīng)匹配出來(lái)的參數(shù),在route函數(shù)里面會(huì)把這些參數(shù)傳給用戶定義的函數(shù)里面,供用戶使用。
_routeToRegExp函數(shù)是一個(gè)簡(jiǎn)單,但要完全理解很難的函數(shù)。這個(gè)函數(shù)的作用就是返回一個(gè)RegExp對(duì)象,通過(guò)這一個(gè)對(duì)象來(lái)匹配當(dāng)前的鏈接,然后從中得到參數(shù)。進(jìn)入這個(gè)函數(shù)之后會(huì)通過(guò)字符串的replace函數(shù),匹配出路由的是哪幾(或一)種情況,并且替代成可以捕獲參數(shù)的正則字符串。比如說(shuō)把路由定義里的/:page或者*fragment這樣的字符串通過(guò)事先定義好的幾個(gè)正則匹配到,然后換成帶()的可以捕獲的形式,然后在創(chuàng)建正則去捕獲真正需要的常數(shù)。
2. Historybackbone中對(duì)于History模塊的使用是通過(guò)用構(gòu)造方式調(diào)用(new)返回一個(gè)可以使用prototype方法的對(duì)象來(lái)實(shí)現(xiàn)的。Backbone.history = new History; 這個(gè)模塊非常重要,而且在整個(gè)backbone里面可以說(shuō)是最難完全讀懂的。下面我會(huì)從三個(gè)方面來(lái)講:一個(gè)方面是有關(guān)于路徑格式處理的問(wèn)題,在這方面也有很多和正則表達(dá)式相關(guān)的函數(shù);另一個(gè)方面是最關(guān)鍵的一個(gè)方面,就是History檢測(cè)瀏覽器來(lái)使用不同的路由控制方式;最后一個(gè)方面就是通過(guò)具體的函數(shù)來(lái)講解它是如何實(shí)現(xiàn)第二點(diǎn)各方面所說(shuō)的控制的。
History從接口的角度來(lái)說(shuō)有start函數(shù)作為初始化的設(shè)置,還有通過(guò)Router模塊封裝的navigate方法。Router里面的很多處理需要調(diào)用到這個(gè)模塊的方法。
History事實(shí)上也是對(duì)location/history一定程度上的封裝。很多時(shí)候是通過(guò)location模塊來(lái)讀取匹配,通過(guò)history的一些方法來(lái)進(jìn)行路由控制。
2.1 路徑格式處理用戶可以設(shè)置root,作為根路徑。這個(gè)根路徑在模塊中有一些判斷和處理的地方。比方說(shuō)確定當(dāng)前是否在根路徑,或者在當(dāng)前URL提取出相應(yīng)的錨點(diǎn)等等都需要用到root這個(gè)內(nèi)部變量。
在這個(gè)函數(shù)里面我們可以看到URL的格式分為了兩種。一種是hash方式,一種是search方式(主要是兼容較老的瀏覽器)。在這里通過(guò)判斷來(lái)進(jìn)行瀏覽器能力檢測(cè)。對(duì)于大部分現(xiàn)代瀏覽器來(lái)說(shuō),事實(shí)上大都是使用hash方式獲取錨點(diǎn)#后面的URL片段。
2.2 路由控制的三種方法(核心)這種方式是通過(guò)監(jiān)聽(tīng)"hashchange"事件,然后觸發(fā)事件,用location.hash.replace方法來(lái)改變路由。
這種方式是最為推薦的HTML5方式。使用history的pushState方法修改history里的記錄,然后也可以通過(guò)監(jiān)聽(tīng)popstate來(lái)觸發(fā)一些相關(guān)的事件。
這是一個(gè)非常巧妙但是從某種程度上非常“丑陋”的方法。丑陋是在它比較吃性能,一方面它有很多dom的操作來(lái)設(shè)置iframe,最重要的方面是它還用了定時(shí)器每隔一小段時(shí)間就檢測(cè),然后就觸發(fā)函數(shù),判斷是否改變等等。插入一個(gè)空的iframe(經(jīng)過(guò)屬性設(shè)置)的作用在這里是存儲(chǔ)hash的值和存儲(chǔ)hash改變記錄。在這里我遇到了一個(gè)問(wèn)題:存儲(chǔ)hash的值完全可以通過(guò)一個(gè)全局變量來(lái)完成,為什么要大費(fèi)周折創(chuàng)建一個(gè)iframe呢?下面是個(gè)人的一些猜測(cè):
Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
這是源碼中的一句注釋。用iframe的理由可能是為了通過(guò)開(kāi)關(guān)iframe來(lái)存儲(chǔ)記錄。說(shuō)實(shí)話具體是什么原理還不清楚,如果有人了解的話歡迎指教~
// 開(kāi)關(guān)`iframe` iWindow.document.open(); iWindow.document.close();2.3 實(shí)現(xiàn)(start, navigate & 事件)
start主要做如下操作:
進(jìn)入start函數(shù)之后會(huì)把started設(shè)置為true防止重復(fù)出發(fā)。
設(shè)置各種參數(shù),用于后期判斷使用哪一種路由控制方式。
如果有hashchange事件,但沒(méi)有pushState方法,就用location.replace方法來(lái)改變路由。如果兩者都有就調(diào)用navigate函數(shù),里面可以通過(guò)pushState改變并記錄路由。如果兩者都沒(méi)有就設(shè)置iframe并啟動(dòng),通過(guò)設(shè)置iframe的hash參數(shù)來(lái)改變路由。
綁定事件,用hashChange方法的綁定hashchange事件,用pushState方法的綁定popstate事件,用iframe的使用setInterval來(lái)監(jiān)聽(tīng)。
進(jìn)入函數(shù)之后首先是進(jìn)行“組合”,“組合”出url。這個(gè)過(guò)程需要有root和fragment,后者需要調(diào)用getFragment函數(shù),前者需要根據(jù)是path還是hash來(lái)對(duì)root進(jìn)行處理。如果是hash就不需要加/,如果是path就要加/。解碼后判斷當(dāng)前的this.fragment和有沒(méi)有發(fā)生變化,沒(méi)有不管,有就更新。
根據(jù)瀏覽器使用不同的方法。注意這里使用的判斷的依據(jù)是在start函數(shù)里面就定義好的。
如果有pushState或者replaceState就用;
如果有hashchange就僅僅只調(diào)用_upadateHash,傳入當(dāng)前的location bom對(duì)象,里面用了location.replace,更新當(dāng)前的href或者hash;
如果沒(méi)有hashchange就需要把當(dāng)前location和iframe.location對(duì)象分別傳入_updateHash,然后更新當(dāng)前href或者hash。
還有一個(gè)需要注意的是是否replace,這是一個(gè)傳入?yún)?shù),判斷時(shí)候要影響history。
關(guān)于路由觸發(fā)事件是通過(guò)兩個(gè)函數(shù)來(lái)完成的,它們分別是checkUrl和loadUrl, 前者會(huì)檢測(cè)路由是否發(fā)生了改變,如果改變了就會(huì)觸發(fā)navigate函數(shù)并調(diào)用loadUrl函數(shù),而后者會(huì)通過(guò)路由片段來(lái)找到handlers相關(guān)的事件函數(shù)來(lái)觸發(fā)。這就實(shí)現(xiàn)了用戶在routes對(duì)象里面設(shè)置的事件了。
3. Sync最后來(lái)個(gè)簡(jiǎn)單的Sync的講解吧~有關(guān)ajax的部分在backbone中其實(shí)是通過(guò)Backbone.ajax函數(shù)來(lái)代理jquery或者其他可以發(fā)起ajax的庫(kù)的。而Sync函數(shù)事實(shí)上主要的工作就是部署ajax參數(shù),最后調(diào)用這個(gè)Backbone.ajax發(fā)起請(qǐng)求。通過(guò)源碼可以看到,其中為params設(shè)置了type, dataType, url, contentType, data, (processData)屬性來(lái)作為發(fā)起ajax的參數(shù)。其中也為options設(shè)置了beforeSend, error方法作為ajax的回調(diào)(success函數(shù)寫(xiě)在其他模塊中,詳情可以看我之前的幾篇文章)。
其中還需要主要的有兩個(gè)參數(shù)emulateJSON & emulateHTTP。在文檔中的介紹非常詳細(xì),個(gè)人覺(jué)得在大部分時(shí)候都不會(huì)用到。
4. 最后的話終于把最后的第三篇文章寫(xiě)出來(lái)了...花了很長(zhǎng)時(shí)間...還是覺(jué)得如果要真正完全讀懂backbone源碼要多讀代碼(慚愧,自認(rèn)為還沒(méi)完全達(dá)到),多查資料,多讀一些源碼解析。有關(guān)于router和history我覺(jué)得這篇文章還是很棒的。這一個(gè)部分個(gè)人感覺(jué)確實(shí)不是很好懂,但是可以學(xué)習(xí)到很多有關(guān)路由的處理的相關(guān)知識(shí),其實(shí)是非常有益的~
backbone被稱(chēng)為框架的框架。這個(gè)框架的思想比起使用更有意義,畢竟現(xiàn)在有更多功能強(qiáng)大的框架。新東西要學(xué),但是經(jīng)典也是不應(yīng)該被落下的。
如果這篇文章有什么錯(cuò)誤的地方請(qǐng)輕噴~互相學(xué)習(xí)!謝謝大家。
下面是全部的文章:
基于 Backbone + node 的個(gè)人簡(jiǎn)歷生成器(個(gè)人學(xué)習(xí)總結(jié))
Backbone源碼解讀(一)
Backbone源碼解讀(二)
Backbone源碼解讀(三)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80287.html
1. 開(kāi)場(chǎng) 1.1 MVC? MVC是一種GUI軟件的一種架構(gòu)模式。它的目的是將軟件的數(shù)據(jù)層(Model)和視圖(view)分開(kāi)。Model連接數(shù)據(jù)庫(kù),實(shí)現(xiàn)數(shù)據(jù)的交互。用戶不能直接和數(shù)據(jù)打交道,而是需要通過(guò)操作視圖,然后通過(guò)controller對(duì)事件作出響應(yīng),最后才得以改變數(shù)據(jù)。最后數(shù)據(jù)改變,通過(guò)觀察者模式更新view。(所以在這里需要用到設(shè)計(jì)模式中的觀察者模式) 1.2 Smalltalk-80...
摘要:以為例構(gòu)造函數(shù)的內(nèi)容構(gòu)造函數(shù)的內(nèi)部一般會(huì)做以下幾個(gè)操作各種給內(nèi)部對(duì)象設(shè)置屬性。為什么呢源碼做出了解釋。在里面會(huì)調(diào)用用戶傳入的回調(diào)函數(shù)并觸發(fā)事件表示已經(jīng)同步了。整個(gè)的源碼事實(shí)上就是這兩組東西。 1. 開(kāi)場(chǎng) 強(qiáng)烈建議一邊看著源碼一邊讀本文章,本文不貼大段代碼。源碼地址。在寫(xiě)backbone應(yīng)用的時(shí)候,說(shuō)實(shí)話,大部分的時(shí)間都是在寫(xiě)這三個(gè)模塊的內(nèi)容。關(guān)于這三個(gè)模塊的分析網(wǎng)上隨隨便便就能找到一堆...
摘要:接受個(gè)參數(shù),包括事件的名稱(chēng),回調(diào)函數(shù)和回調(diào)函數(shù)執(zhí)行的上下文環(huán)境。保留回調(diào)函數(shù)在數(shù)組中取出對(duì)應(yīng)的以及中的函數(shù)。當(dāng)然,你同樣可以在綁定的回調(diào)函數(shù)執(zhí)行前手動(dòng)通過(guò)將其移除。 Backbone源碼解讀 Backbone在流行的前端框架中是最輕量級(jí)的一個(gè),全部代碼實(shí)現(xiàn)一共只有1831行1。從前端的入門(mén)再到Titanium,我雖然幾次和Backbone打交道但是卻對(duì)它的結(jié)構(gòu)知之甚少,也促成了我想讀...
摘要:個(gè)人認(rèn)為,讀懂老牌框架的源代碼比會(huì)用流行框架的要有用的多。另外,源代碼中所有的以開(kāi)頭的方法,可以認(rèn)為是私有方法,是沒(méi)有必要直接使用的,也不建議用戶覆蓋。 寫(xiě)在前面 backbone是我兩年多前入門(mén)前端的時(shí)候接觸到的第一個(gè)框架,當(dāng)初被backbone的強(qiáng)大功能所吸引(當(dāng)然的確比裸寫(xiě)js要好得多),雖然現(xiàn)在backbone并不算最主流的前端框架了,但是,它里面大量設(shè)計(jì)模式的靈活運(yùn)用,以及令...
摘要:個(gè)人認(rèn)為,讀懂老牌框架的源代碼比會(huì)用流行框架的要有用的多。另外,源代碼中所有的以開(kāi)頭的方法,可以認(rèn)為是私有方法,是沒(méi)有必要直接使用的,也不建議用戶覆蓋。 寫(xiě)在前面 backbone是我兩年多前入門(mén)前端的時(shí)候接觸到的第一個(gè)框架,當(dāng)初被backbone的強(qiáng)大功能所吸引(當(dāng)然的確比裸寫(xiě)js要好得多),雖然現(xiàn)在backbone并不算最主流的前端框架了,但是,它里面大量設(shè)計(jì)模式的靈活運(yùn)用,以及令...
閱讀 2548·2023-04-25 17:27
閱讀 1857·2019-08-30 15:54
閱讀 2402·2019-08-30 13:06
閱讀 3008·2019-08-30 11:04
閱讀 783·2019-08-29 15:30
閱讀 756·2019-08-29 15:16
閱讀 1766·2019-08-26 10:10
閱讀 3631·2019-08-23 17:02