前端路由

什么是前端路由
路由迫悠,引導(dǎo)、指路之意于购。

譬如我們熟知的路由器袍睡,蹦跶在網(wǎng)絡(luò)層的數(shù)據(jù)包轉(zhuǎn)發(fā)設(shè)備,在網(wǎng)絡(luò)中也是扮演著指路明燈的角色肋僧,肩負(fù)著將數(shù)據(jù)包正確導(dǎo)向目的地址的重任斑胜。

前端路由也借用了這個(gè)詞,但是承擔(dān)的工作全然不同嫌吠,它是服務(wù)于客戶端瀏覽器的指路人止潘。

所謂的前端路由,擁有這樣一種能力:客戶端瀏覽器可以不依賴服務(wù)端辫诅,根據(jù)不同的URL渲染不同的視圖頁面凭戴。

前端路由的存在合理性
在Ajax之劍還未亮出,前端仍處于襁褓之中的時(shí)候炕矮,路由的工作交給了后端簇宽。在進(jìn)行頁面切換的時(shí)候,瀏覽器發(fā)送不同的url請求吧享;服務(wù)器接收到瀏覽器的請求時(shí),通過解析不同的url去拼接需要的html或者模板譬嚣,然后將結(jié)果返回給瀏覽器端進(jìn)行渲染钢颂。

服務(wù)器端路由也是不落俗套的有利亦有弊。它的好處是安全性更高拜银,更嚴(yán)格得控制頁面的展現(xiàn)殊鞭。這在某些場景中是很有用的,譬如下單支付流程尼桶,每一步只有在上一步成功執(zhí)行之后才能抵達(dá)操灿。這在服務(wù)器端可以為每一步流程添加驗(yàn)證機(jī)制,只有驗(yàn)證通過才返回正確的頁面泵督。那么前端路由不能實(shí)現(xiàn)每一步的驗(yàn)證趾盐?自然不是,姑且相信你的代碼可以寫的很嚴(yán)謹(jǐn)小腊,保證正常情況下流程不會錯救鲤,但是另一個(gè)不得不面對的事實(shí)是:前端是毫無安全性可言的。用戶可以肆意修改代碼來進(jìn)入不同的流程秩冈,你可能會為此添加不少的處理邏輯本缠。相較之下,當(dāng)然是后端控制頁面的進(jìn)入權(quán)限更為安全和簡便入问。

另一方面丹锹,后端路由無疑增加了服務(wù)器端的負(fù)荷稀颁,并且需要reload頁面,用戶體驗(yàn)其實(shí)不佳楣黍。

這樣匾灶,前端路由就有用武之地了。首先锡凝,它的出現(xiàn)無疑減輕了服務(wù)器端的壓力粘昨。特別是對于一個(gè)比較復(fù)雜的應(yīng)用來講,或者更確切的說窜锯,對于擁有一個(gè)復(fù)雜路由系統(tǒng)的應(yīng)用來說张肾,服務(wù)器端需要為每一個(gè)不同的url執(zhí)行一段處理邏輯在高并發(fā)的情況下實(shí)在有點(diǎn)不堪重負(fù);其次锚扎,頁面的切換可以不需要刷新整個(gè)頁面了吞瞪,沒有網(wǎng)絡(luò)延遲,沒有閃爍刷新驾孔,提升了用戶體驗(yàn)芍秆。

前端路由實(shí)現(xiàn)方式
既然目標(biāo)實(shí)現(xiàn),我們需要解決的問題有哪些翠勉?我們可以將問題拆的稍微細(xì)一點(diǎn)妖啥,先制定一個(gè)億的小計(jì)劃,實(shí)現(xiàn)之后再進(jìn)行下一步:)

  • 在頁面不刷新的前提下實(shí)現(xiàn)url變化
  • 捕捉到url的變化对碌,以便執(zhí)行頁面替換邏輯

如何實(shí)現(xiàn)更新url并且頁面不刷新
正如前面所說荆虱,前端路由相較于后端路由的一個(gè)特點(diǎn)就是頁面在不完全刷新的情況下進(jìn)行視圖的切換。頁面url變了朽们,但是并沒有重新加載怀读!看上去似乎有點(diǎn)不可思議,其實(shí)也沒什么大不了骑脱。

試想將瀏覽器地址欄當(dāng)做一個(gè)輸入框菜枷,我們需要實(shí)現(xiàn)的就是改變輸入框的value但是不觸發(fā)請求頁面的操作,這樣就不會重新加載新頁面叁丧。倘若輸入框的值的變化和發(fā)送請求是一個(gè)原子操作啤誊,我們也就束手無策了。慶幸的是拥娄,只有當(dāng)我們敲擊了回車之后坷衍,請求才會被發(fā)送出去(這是顯而易見的吧)。因此這就為我們修改地址欄的值而不觸發(fā)頁面請求刷新創(chuàng)造了條件条舔。BOM是否有提供修改瀏覽器地址欄url而不觸發(fā)請求操作的方法呢枫耳?

這里,存在兩種滿足需求的方式孟抗。一是利用url中的hash字段迁杨;二是使用html5提供的history API钻心。

hash方式
了解http協(xié)議就會知道,url的組成部分有很多铅协,譬如協(xié)議捷沸、主機(jī)名、資源路徑狐史、查詢字段等等痒给,其中包含一個(gè)稱之為片段的部分,以“#”為標(biāo)識骏全。

例如:http://www.gmail.com/text/#123苍柏,123便是url中的hash部分。

打開控制臺姜贡,輸入 location.hash试吁,你可以得到當(dāng)前url的hash部分(如果當(dāng)前url不存在hash則返回空字符串)。接下來楼咳,輸入 location.hash = '123'熄捍,會發(fā)現(xiàn)瀏覽器地址欄的url變了,末尾增加了’#123’字段母怜,并且余耽,頁面沒有被重新刷新。很顯然苹熏,這很符合我們的要求碟贾。

history API
html5引入了一個(gè)history對象,包含了一套訪問瀏覽器歷史的api柜裸,可以通過window.history訪問到它。

這里我們看上了它的兩個(gè)api方法:pushState 和 replaceState粱锐。


若上所示疙挺,它們接收完全相同的參數(shù),都是對瀏覽器的歷史棧進(jìn)行操作怜浅,將傳遞的url和相關(guān)數(shù)據(jù)壓棧铐然,并將瀏覽器地址欄的url替換成傳入的url且不刷新頁面(正中下懷!)恶座。

By the way搀暑,不同的地方是pushState 將指定的url直接壓入歷史記錄棧頂,而 replaceState 是將當(dāng)前歷史記錄棧頂替換成傳入的數(shù)據(jù)跨琳。

這兩種方式都可以幫我們滿足題設(shè)條件自点。采用哪一種方式除了主觀喜好之外,還得依照客觀事實(shí):低版本的瀏覽器對于history API的兼容性不好脉让,例如遇到了IE8桂敛,擺在眼前的道路似乎就別無選擇了功炮。

如何跟蹤url變化
在瀏覽器端,跟蹤表單屬性的變化一般都采用事件監(jiān)聽機(jī)制术唬,跟蹤url的變化也不落俗套薪伏。

對于hash方式的前端路由,通炒植郑可以監(jiān)聽 hashchange 事件嫁怀,在事件回調(diào)中處理相應(yīng)的頁面視圖展示等邏輯。

此外借浊,html5提供的 popstate 事件也會在url的hash發(fā)生改變時(shí)觸發(fā)塘淑。也就是說如果可以忽略低版本瀏覽器,我們使用hash方式路由時(shí)也可以采用監(jiān)聽這個(gè)事件進(jìn)行回調(diào)處理巴碗。

那么朴爬,如果是采用history API的形式呢?根據(jù)MDN的描述:

調(diào)用 history.pushState() 或者 history.replaceState() 不會觸發(fā) popstate 事件橡淆。popstate 事件只會在瀏覽器某些行為下觸發(fā), 比如點(diǎn)擊后退按鈕(或者在JavaScript中調(diào)用 history.back() 方法)召噩。

這也就是說,我們在使用history API改變?yōu)g覽器的url時(shí)逸爵,仍需要額外的步驟去觸發(fā) popstate 事件具滴,例如調(diào)用 history.back() 會 history.forward() 等方法。

從兼容性上來講师倔,前面有提及hash的方式兼容性更好构韵。然而,對于低版本的瀏覽器趋艘,例如IE6等等疲恢,不支持 hashchange 事件。這個(gè)時(shí)候我們只能通過 setInterval 設(shè)置心跳的方式去模擬 hashchange瓷胧。


一個(gè)簡單實(shí)現(xiàn)
這里显拳,給出一個(gè)很簡單的實(shí)現(xiàn):

router.js


index.html


index.js


一點(diǎn)總結(jié)
應(yīng)用場景
前端路由大部分的應(yīng)用場景,就是我們現(xiàn)在熟知的單頁應(yīng)用SPA搓萧。

不存在純前端路由
我們此前所描述的前端路由杂数,建立在已經(jīng)打開了一個(gè)初始頁面基礎(chǔ)之上,然后在這個(gè)頁面之內(nèi)進(jìn)行頁面替換瘸洛。然而揍移,我們?nèi)绾芜M(jìn)入這個(gè)初始頁面?僅靠前端路由肯定是力所不及反肋。我們至少要向后端發(fā)送一次http請求那伐,接收所需要加載的頁面不是嗎?

所以,我們并不能拋棄后端路由部分喧锦。這也意味著读规,我們需要和后端確認(rèn)各自的分工,哪些url歸前端解析燃少,哪些歸后臺解析束亏。

關(guān)于本文
作者:@陶天然
原文:http://tomasran.space/archives/1bjDjwd2FgzJIsCyshbzag/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市阵具,隨后出現(xiàn)的幾起案子碍遍,更是在濱河造成了極大的恐慌,老刑警劉巖阳液,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怕敬,死亡現(xiàn)場離奇詭異,居然都是意外死亡帘皿,警方通過查閱死者的電腦和手機(jī)东跪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹰溜,“玉大人虽填,你說我怎么就攤上這事〔芏” “怎么了斋日?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長墓陈。 經(jīng)常有香客問我恶守,道長,這世上最難降的妖魔是什么贡必? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任兔港,我火速辦了婚禮,結(jié)果婚禮上仔拟,老公的妹妹穿的比我還像新娘衫樊。我一直安慰自己,他們只是感情好理逊,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布橡伞。 她就那樣靜靜地躺著盒揉,像睡著了一般晋被。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刚盈,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天羡洛,我揣著相機(jī)與錄音,去河邊找鬼。 笑死欲侮,一個(gè)胖子當(dāng)著我的面吹牛崭闲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播威蕉,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼刁俭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了韧涨?” 一聲冷哼從身側(cè)響起牍戚,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虑粥,沒想到半個(gè)月后如孝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娩贷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年第晰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彬祖。...
    茶點(diǎn)故事閱讀 40,769評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茁瘦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涧至,到底是詐尸還是另有隱情腹躁,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布南蓬,位于F島的核電站纺非,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赘方。R本人自食惡果不足惜烧颖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窄陡。 院中可真熱鬧炕淮,春花似錦、人聲如沸跳夭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽币叹。三九已至润歉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颈抚,已是汗流浹背踩衩。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驱富。 一個(gè)月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓锚赤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親褐鸥。 傳聞我的和親對象是個(gè)殘疾皇子线脚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評論 2 361

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