摘要:事件關于路由觸發事件是通過兩個函數來完成的,它們分別是和前者會檢測路由是否發生了改變,如果改變了就會觸發函數并調用函數,而后者會通過路由片段來找到相關的事件函數來觸發。
注意:強烈建議一邊閱讀源碼一邊閱讀本文。
終于到了backbone源碼解讀的最后一篇,這一篇和前面幾篇時間上有一定的間隔(因為要回學校有一堆亂七八糟的事...)。在這一篇里面會講解Bakcbone的sync & router & histrory。sync比較簡單,但是路由的部分就比較復雜了。個人覺得是整個backbone源碼里面最不好懂的一個部分,這個部分也使得backbone可以方便實現可以“返回”的單頁面應用。個人覺得這個部分其實并沒有很MVC有很密切的關系,但是它非常重要。讀過源碼就會發現,其實這一個部分與其他的模塊(Model,Collection & View)相對獨立。如果不希望使用backbone但希望能用到這個路由系統的話估計拆出來難度也不會很大。
總體來說路由模塊由Router和Histrory組成,而Router事實上可以看成是對History的一個封裝。用戶直接操作的部分時Router,相關函數的處理(路由匹配時調用的函數)也是在Router中完成。History主要是處理一個更加棘手的問題,就是有關鏈接的問題。這里面有關于跨瀏覽器的解決方案是非常值得學習的。
1. RouterRouter是對History的封裝,也是給用戶定義路由的接口。一般來說,用戶在使用Router的時候會定義一個routers的對象,里面是想關路由與處理函數組成的key-value。Router代碼中主要做兩件事,一件是對正則表達式的操作(可以看見里面很多令人痛苦的正則表達式),另一件事就是事件相關的綁定了。Router的相關代碼不多,寫得比較精簡。
1.1 函數綁定與執行Router里面定義了兩種方法來定義路由事件,一個方法是用戶定義routers,通過初始化調用_bindRoutes函數;一個方法是用自帶的route函數。其實兩個方法本質上都是調用了route函數,_bindRoutes里面實際上也是通過循環來調用route函數。因此路由函數重點在于route函數。
在route函數里面,一開始是進行一些參數的整理。然后就是調用了History模塊的route函數,把正則(匹配參數用的)和一個回調函數傳了進去。在回調函數里面就是做 執行函數——觸發router的事件——觸發history的事件這幾個步驟,在History的route函數里面,只是簡單的插入地把key和callback組成對象插入handlers數組里面而已。
1.2. 正則表達式轉化與使用Router函數里面最難懂也非常重要的部分是格式的轉換。在Router里面有兩個重要的函數_routeToRegExp函數和_extractParameters兩個,這兩個函數與正則密切相關。
_extractParameters函數的作用是利用正則表達式,把傳進來的url片段fragment分割成片段存進數組當中。這些片段是真實的已經匹配出來的參數,在route函數里面會把這些參數傳給用戶定義的函數里面,供用戶使用。
_routeToRegExp函數是一個簡單,但要完全理解很難的函數。這個函數的作用就是返回一個RegExp對象,通過這一個對象來匹配當前的鏈接,然后從中得到參數。進入這個函數之后會通過字符串的replace函數,匹配出路由的是哪幾(或一)種情況,并且替代成可以捕獲參數的正則字符串。比如說把路由定義里的/:page或者*fragment這樣的字符串通過事先定義好的幾個正則匹配到,然后換成帶()的可以捕獲的形式,然后在創建正則去捕獲真正需要的常數。
2. Historybackbone中對于History模塊的使用是通過用構造方式調用(new)返回一個可以使用prototype方法的對象來實現的。Backbone.history = new History; 這個模塊非常重要,而且在整個backbone里面可以說是最難完全讀懂的。下面我會從三個方面來講:一個方面是有關于路徑格式處理的問題,在這方面也有很多和正則表達式相關的函數;另一個方面是最關鍵的一個方面,就是History檢測瀏覽器來使用不同的路由控制方式;最后一個方面就是通過具體的函數來講解它是如何實現第二點各方面所說的控制的。
History從接口的角度來說有start函數作為初始化的設置,還有通過Router模塊封裝的navigate方法。Router里面的很多處理需要調用到這個模塊的方法。
History事實上也是對location/history一定程度上的封裝。很多時候是通過location模塊來讀取匹配,通過history的一些方法來進行路由控制。
2.1 路徑格式處理用戶可以設置root,作為根路徑。這個根路徑在模塊中有一些判斷和處理的地方。比方說確定當前是否在根路徑,或者在當前URL提取出相應的錨點等等都需要用到root這個內部變量。
在這個函數里面我們可以看到URL的格式分為了兩種。一種是hash方式,一種是search方式(主要是兼容較老的瀏覽器)。在這里通過判斷來進行瀏覽器能力檢測。對于大部分現代瀏覽器來說,事實上大都是使用hash方式獲取錨點#后面的URL片段。
2.2 路由控制的三種方法(核心)這種方式是通過監聽"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();2.3 實現(start, navigate & 事件)
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對象里面設置的事件了。
3. Sync最后來個簡單的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。在文檔中的介紹非常詳細,個人覺得在大部分時候都不會用到。
4. 最后的話終于把最后的第三篇文章寫出來了...花了很長時間...還是覺得如果要真正完全讀懂backbone源碼要多讀代碼(慚愧,自認為還沒完全達到),多查資料,多讀一些源碼解析。有關于router和history我覺得這篇文章還是很棒的。這一個部分個人感覺確實不是很好懂,但是可以學習到很多有關路由的處理的相關知識,其實是非常有益的~
backbone被稱為框架的框架。這個框架的思想比起使用更有意義,畢竟現在有更多功能強大的框架。新東西要學,但是經典也是不應該被落下的。
如果這篇文章有什么錯誤的地方請輕噴~互相學習!謝謝大家。
下面是全部的文章:
基于 Backbone + node 的個人簡歷生成器(個人學習總結)
Backbone源碼解讀(一)
Backbone源碼解讀(二)
Backbone源碼解讀(三)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80287.html
1. 開場 1.1 MVC? MVC是一種GUI軟件的一種架構模式。它的目的是將軟件的數據層(Model)和視圖(view)分開。Model連接數據庫,實現數據的交互。用戶不能直接和數據打交道,而是需要通過操作視圖,然后通過controller對事件作出響應,最后才得以改變數據。最后數據改變,通過觀察者模式更新view。(所以在這里需要用到設計模式中的觀察者模式) 1.2 Smalltalk-80...
摘要:以為例構造函數的內容構造函數的內部一般會做以下幾個操作各種給內部對象設置屬性。為什么呢源碼做出了解釋。在里面會調用用戶傳入的回調函數并觸發事件表示已經同步了。整個的源碼事實上就是這兩組東西。 1. 開場 強烈建議一邊看著源碼一邊讀本文章,本文不貼大段代碼。源碼地址。在寫backbone應用的時候,說實話,大部分的時間都是在寫這三個模塊的內容。關于這三個模塊的分析網上隨隨便便就能找到一堆...
摘要:接受個參數,包括事件的名稱,回調函數和回調函數執行的上下文環境。保留回調函數在數組中取出對應的以及中的函數。當然,你同樣可以在綁定的回調函數執行前手動通過將其移除。 Backbone源碼解讀 Backbone在流行的前端框架中是最輕量級的一個,全部代碼實現一共只有1831行1。從前端的入門再到Titanium,我雖然幾次和Backbone打交道但是卻對它的結構知之甚少,也促成了我想讀...
摘要:個人認為,讀懂老牌框架的源代碼比會用流行框架的要有用的多。另外,源代碼中所有的以開頭的方法,可以認為是私有方法,是沒有必要直接使用的,也不建議用戶覆蓋。 寫在前面 backbone是我兩年多前入門前端的時候接觸到的第一個框架,當初被backbone的強大功能所吸引(當然的確比裸寫js要好得多),雖然現在backbone并不算最主流的前端框架了,但是,它里面大量設計模式的靈活運用,以及令...
摘要:個人認為,讀懂老牌框架的源代碼比會用流行框架的要有用的多。另外,源代碼中所有的以開頭的方法,可以認為是私有方法,是沒有必要直接使用的,也不建議用戶覆蓋。 寫在前面 backbone是我兩年多前入門前端的時候接觸到的第一個框架,當初被backbone的強大功能所吸引(當然的確比裸寫js要好得多),雖然現在backbone并不算最主流的前端框架了,但是,它里面大量設計模式的靈活運用,以及令...
閱讀 2513·2023-04-25 17:27
閱讀 1824·2019-08-30 15:54
閱讀 2369·2019-08-30 13:06
閱讀 2980·2019-08-30 11:04
閱讀 746·2019-08-29 15:30
閱讀 729·2019-08-29 15:16
閱讀 1733·2019-08-26 10:10
閱讀 3603·2019-08-23 17:02