注意:強烈建議一邊閱讀源碼一邊閱讀本文。html
終於到了backbone
源碼解讀的最後一篇,這一篇和前面幾篇時間上有必定的間隔(由於要回學校有一堆亂七八糟的事...)。在這一篇裏面會講解Bakcbone
的sync
& router
& histrory
。sync
比較簡單,可是路由的部分就比較複雜了。我的以爲是整個backbone
源碼裏面最很差懂的一個部分,這個部分也使得backbone
能夠方便實現能夠「返回」的單頁面應用。我的以爲這個部分其實並無很MVC
有很密切的關係,可是它很是重要。讀過源碼就會發現,其實這一個部分與其餘的模塊(Model
,Collection
& View
)相對獨立。若是不但願使用backbone
但但願能用到這個路由系統的話估計拆出來難度也不會很大。node
整體來講路由模塊由Router
和Histrory
組成,而Router
事實上能夠當作是對History
的一個封裝。用戶直接操做的部分時Router
,相關函數的處理(路由匹配時調用的函數)也是在Router
中完成。History
主要是處理一個更加棘手的問題,就是有關連接的問題。這裏面有關於跨瀏覽器的解決方案是很是值得學習的。jquery
Router
是對History
的封裝,也是給用戶定義路由的接口。通常來講,用戶在使用Router
的時候會定義一個routers
的對象,裏面是想關路由與處理函數組成的key-value
。Router
代碼中主要作兩件事,一件是對正則表達式的操做(能夠看見裏面不少使人痛苦的正則表達式),另外一件事就是事件相關的綁定了。Router
的相關代碼很少,寫得比較精簡。git
Router
裏面定義了兩種方法來定義路由事件,一個方法是用戶定義routers
,經過初始化調用_bindRoutes
函數;一個方法是用自帶的route
函數。其實兩個方法本質上都是調用了route
函數,_bindRoutes
裏面實際上也是經過循環來調用route
函數。所以路由函數重點在於route
函數。github
在route
函數裏面,一開始是進行一些參數的整理。而後就是調用了History
模塊的route
函數,把正則(匹配參數用的)和一個回調函數傳了進去。在回調函數裏面就是作 執行函數
——觸發router的事件
——觸發history的事件
這幾個步驟,在History
的route
函數裏面,只是簡單的插入地把key
和callback
組成對象插入handlers
數組裏面而已。ajax
Router
函數裏面最難懂也很是重要的部分是格式的轉換。在Router
裏面有兩個重要的函數_routeToRegExp
函數和_extractParameters
兩個,這兩個函數與正則密切相關。正則表達式
_extractParameters
函數的做用是利用正則表達式,把傳進來的url
片斷fragment
分割成片斷存進數組當中。這些片斷是真實的已經匹配出來的參數,在route
函數裏面會把這些參數傳給用戶定義的函數裏面,供用戶使用。segmentfault
_routeToRegExp
函數是一個簡單,但要徹底理解很難的函數。這個函數的做用就是返回一個RegExp
對象,經過這一個對象來匹配當前的連接,而後從中獲得參數。進入這個函數以後會經過字符串的replace
函數,匹配出路由的是哪幾(或一)種狀況,而且替代成能夠捕獲參數的正則字符串。好比說把路由定義裏的/:page
或者*fragment
這樣的字符串經過事先定義好的幾個正則匹配到,而後換成帶()
的能夠捕獲的形式,而後在建立正則去捕獲真正須要的常數。api
backbone
中對於History
模塊的使用是經過用構造方式調用(new)
返回一個可使用prototype
方法的對象來實現的。Backbone.history = new History;
這個模塊很是重要,並且在整個backbone
裏面能夠說是最難徹底讀懂的。下面我會從三個方面來說:一個方面是有關於路徑格式處理的問題,在這方面也有不少和正則表達式相關的函數;另外一個方面是最關鍵的一個方面,就是History
檢測瀏覽器來使用不一樣的路由控制方式;最後一個方面就是經過具體的函數來說解它是如何實現第二點各方面所說的控制的。數組
History
從接口的角度來講有start
函數做爲初始化的設置,還有經過Router
模塊封裝的navigate
方法。Router
裏面的不少處理須要調用到這個模塊的方法。
History
事實上也是對location/history
必定程度上的封裝。不少時候是經過location
模塊來讀取匹配,經過history
的一些方法來進行路由控制。
用戶能夠設置root
,做爲根路徑。這個根路徑在模塊中有一些判斷和處理的地方。比方說肯定當前是否在根路徑,或者在當前URL
提取出相應的錨點等等都須要用到root
這個內部變量。
在這個函數裏面咱們能夠看到URL
的格式分爲了兩種。一種是hash
方式,一種是search
方式(主要是兼容較老的瀏覽器)。在這裏經過判斷來進行瀏覽器能力檢測。對於大部分現代瀏覽器來講,事實上大都是使用hash
方式獲取錨點#
後面的URL
片斷。
這種方式是經過監聽'hashchange'
事件,而後觸發事件,用location.hash.replace
方法來改變路由。
這種方式是最爲推薦的HTML5
方式。使用history
的pushState
方法修改history
裏的記錄,而後也能夠經過監聽popstate
來觸發一些相關的事件。
這是一個很是巧妙可是從某種程度上很是「醜陋」的方法。醜陋是在它比較吃性能,一方面它有不少dom
的操做來設置iframe
,最重要的方面是它還用了定時器每隔一小段時間就檢測,而後就觸發函數,判斷是否改變等等。插入一個空的iframe
(通過屬性設置)的做用在這裏是存儲hash
的值和存儲hash
改變記錄。在這裏我遇到了一個問題:存儲hash
的值徹底能夠經過一個全局變量來完成,爲何要大費周折建立一個iframe
呢?下面是我的的一些猜想:
Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
這是源碼中的一句註釋。用iframe
的理由多是爲了經過開關iframe
來存儲記錄。說實話具體是什麼原理還不清楚,若是有人瞭解的話歡迎指教~
// 開關`iframe` iWindow.document.open(); iWindow.document.close();
start
主要作以下操做:
進入start
函數以後會把started
設置爲true
防止重複出發。
設置各類參數,用於後期判斷使用哪種路由控制方式。
若是有hashchange
事件,但沒有pushState
方法,就用location.replace
方法來改變路由。若是二者都有就調用navigate
函數,裏面能夠經過pushState
改變並記錄路由。若是二者都沒有就設置iframe
並啓動,經過設置iframe
的hash
參數來改變路由。
綁定事件,用hashChange
方法的綁定hashchange
事件,用pushState
方法的綁定popstate
事件,用iframe
的使用setInterval
來監聽。
進入函數以後首先是進行「組合」,「組合」出url
。這個過程須要有root
和fragment
,後者須要調用getFragment
函數,前者須要根據是path
仍是hash
來對root
進行處理。若是是hash
就不須要加/
,若是是path
就要加/
。解碼後判斷當前的this.fragment
和有沒有發生變化,沒有無論,有就更新。
根據瀏覽器使用不一樣的方法。注意這裏使用的判斷的依據是在start
函數裏面就定義好的。
若是有pushState
或者replaceState
就用;
若是有hashchange
就僅僅只調用_upadateHash
,傳入當前的location
bom
對象,裏面用了location.replace
,更新當前的href
或者hash
;
若是沒有hashchange
就須要把當前location
和iframe.location
對象分別傳入_updateHash
,而後更新當前href
或者hash
。
還有一個須要注意的是是否replace
,這是一個傳入參數,判斷時候要影響history
。
關於路由觸發事件是經過兩個函數來完成的,它們分別是checkUrl
和loadUrl
, 前者會檢測路由是否發生了改變,若是改變了就會觸發navigate
函數並調用loadUrl
函數,然後者會經過路由片斷來找到handlers
相關的事件函數來觸發。這就實現了用戶在routes
對象裏面設置的事件了。
最後來個簡單的Sync
的講解吧~有關ajax
的部分在backbone
中實際上是經過Backbone.ajax
函數來代理jquery
或者其餘能夠發起ajax
的庫的。而Sync
函數事實上主要的工做就是部署ajax
參數,最後調用這個Backbone.ajax
發起請求。經過源碼能夠看到,其中爲params
設置了type
, dataType
, url
, contentType
, data
, (processData
)屬性來做爲發起ajax
的參數。其中也爲options
設置了beforeSend
, error
方法做爲ajax
的回調(success
函數寫在其餘模塊中,詳情能夠看我以前的幾篇文章)。
其中還須要主要的有兩個參數emulateJSON
& emulateHTTP
。在文檔中的介紹很是詳細,我的以爲在大部分時候都不會用到。
終於把最後的第三篇文章寫出來了...花了很長時間...仍是以爲若是要真正徹底讀懂backbone
源碼要多讀代碼(慚愧,自認爲還沒徹底達到),多查資料,多讀一些源碼解析。有關於router
和history
我以爲這篇文章仍是很棒的。這一個部分我的感受確實不是很好懂,可是能夠學習到不少有關路由的處理的相關知識,實際上是很是有益的~
backbone
被稱爲框架的框架。這個框架的思想比起使用更有意義,畢竟如今有更多功能強大的框架。新東西要學,可是經典也是不該該被落下的。
若是這篇文章有什麼錯誤的地方請輕噴~互相學習!謝謝你們。
下面是所有的文章:
基於 Backbone + node 的我的簡歷生成器(我的學習總結)
Backbone源碼解讀(一)
Backbone源碼解讀(二)
Backbone源碼解讀(三)