天天看點

你好,談談你對前端路由的了解

一篇文章,不可能做的面面俱到,全部閱聽人。希望大家帶着發散思維去看文章,将文章涉及的知識點,吸收為己所用。這樣看完一篇文章,才能有所收獲。

好了不裝了,今天我就化身性感面試官線上問大家一個問題,“談談你對前端路由的了解”。看到這個問題,那回答可多了去了。但是換位思考一下,你問候選人這個問題的時候,你想要得到什麼答案?以我個人拙見,我希望候選人能從全局解讀這個問題,大緻以下三點。

1、為什麼會出現前端路由。

2、前端路由解決了什麼問題。

3、前端路由實作的原理是什麼。

我們帶着這三個問題,繼續往下看,閱讀的過程中如果同學們有自己的見解,可以評論區發表自己的看法。如果覺得講的内容讓你有了新的見解,請獻上你寶貴的一贊????,這将是我繼續寫作的動力。

這裡不糾結叫法,凡是整個項目都是 <code>DOM</code> 直出的頁面,我們都稱它為“傳統頁面”(其 屬于首屏直出,這裡我不認為是傳統頁面的範疇)。那麼什麼是 <code>DOM</code> 直出呢?簡單說就是在浏覽器輸入網址後發起請求,傳回來的 <code>HTML</code> 頁面是最終呈現的效果,那就是 <code>DOM</code> 直出。并且每次點選頁面跳轉,都會重新請求 <code>HTML</code> 資源。耳聽為虛,眼見為實。我們以這個位址為例,驗證以下上述說法。

你好,談談你對前端路由的了解

定眼一看,就能明白上圖在描述什麼。沒錯,部落格園就是一個傳統頁面搭建而成的網站,每次加載頁面,都會傳回 <code>HTML</code> 資源以及裡面的 <code>CSS</code> 等靜态資源,組合成一個新的頁面。

“瞎了”的同學,我再教一個方法,就是在浏覽器頁面右鍵,點選“顯示網頁源代碼”,打開後如下所示:

你好,談談你對前端路由的了解

網頁上能看到什麼圖檔或文字,你能在上述圖檔中找到相應的 <code>HTML</code> 結構,那也屬于傳統頁面,也就是 <code>DOM</code> 直出。

時代在進步,科技在發展,面對日益增長的網頁需求,網頁開始走向子產品化、元件化的道路。随之而來的是代碼的難以維護、不可控、疊代艱難等現象。面臨這種情況,催生出不少優秀的現代前端架構,首當其沖的便是 <code>React</code> 、 <code>Vue</code> 、 <code>Angular</code> 等著名單頁面應用架構。而這些架構有一個共同的特點,便是“通過 JS 渲染頁面”。

舉個例子,以前我們直出 <code>DOM</code> ,而現在運用這些單頁面架構之後, <code>HTML</code> 頁面基本上隻有一個 <code>DOM</code> 入口,大緻如下所示:

你好,談談你對前端路由的了解

所有的頁面元件,都是通過運作上圖底部的 <code>app.js</code> 腳本,挂載到 <code>&lt;div id="root"&gt;&lt;/div&gt;</code> 這個節點下面。用一個極其簡單的 JS 展示挂載這一個步驟:

你好,談談你對前端路由的了解

image.png

脫去所有的凡塵世俗,最本真的單頁項目運作形式便是如此。注意,我要點題了啊!!!

你好,談談你對前端路由的了解

既然單頁面是這樣渲染的,那如果我有十幾個頁面要互相跳轉切換,咋整!!??這時候 前端路由 應運而生,它的出現就是為了解決單頁面網站,通過切換浏覽器位址路徑,來比對相對應的頁面元件。我們通過一張醜陋的圖檔來了解這個過程:

你好,談談你對前端路由的了解

前端路由 會根據浏覽器位址欄 <code>pathname</code> 的變化,去比對相應的頁面元件。然後将其通過建立 <code>DOM</code> 節點的形式,塞入根節點 <code>&lt;div id="root"&gt;&lt;/div&gt;</code> 。這就達到了無重新整理頁面切換的效果,從側面也能說明正因為無重新整理,是以 <code>React</code> 、 <code>Vue</code> 、 <code>Angular</code> 等現代架構在建立頁面元件的時候,每個元件都有自己的 生命周期 。

前端路由 插件比較火的倆架構對應的就是 <code>Vue-Router</code> 和 <code>React-Router</code> ,但是它們的邏輯,歸根結底還是一樣的,用殊途同歸四個字,再合适不過。

通過分析哈希模式和曆史模式的實作原理,讓大家對前端路由的原理有一個更深刻的了解。

<code>a</code> 标簽錨點大家應該不陌生,而浏覽器位址上 <code>#</code> 後面的變化,是可以被監聽的,浏覽器為我們提供了原生監聽事件 <code>hashchange</code> ,它可以監聽到如下的變化:

點選 <code>a</code> 标簽,改變了浏覽器位址

浏覽器的前進後退行為

通過 <code>window.location</code> 方法,改變浏覽器位址

接下來我們利用這些特點,去實作一個 <code>hash</code> 模式的簡易路由:線上運作

當然,這是很簡單的實作,真正的 hash 模式,還要考慮到很多複雜的情況,大家有興趣就去看看源碼。

浏覽器展示效果如下:

你好,談談你對前端路由的了解

<code>history</code> 模式會比 <code>hash</code> 模式稍麻煩一些,因為 <code>history</code> 模式依賴的是原生事件 <code>popstate</code> ,下面是來自 MDN 的解釋:

你好,談談你對前端路由的了解
小知識:pushState 和 replaceState 都是 HTML5 的新 API,他們的作用很強大,可以做到改變浏覽器位址卻不重新整理頁面。這是實作改變位址欄卻不重新整理頁面的重要方法。

包括 <code>a</code> 标簽的點選事件也是不會被 <code>popstate</code> 監聽。我們需要想個辦法解決這個問題,才能實作 <code>history</code> 模式。

你好,談談你對前端路由的了解

**解決思路:**我們可以通過周遊頁面上的所有 <code>a</code> 标簽,阻止 <code>a</code> 标簽的預設事件的同時,加上點選事件的回調函數,在回調函數内擷取 <code>a</code> 标簽的 <code>href</code> 屬性值,再通過 <code>pushState</code> 去改變浏覽器的 <code>location.pathname</code> 屬性值。然後手動執行 <code>popstate</code> 事件的回調函數,去比對相應的路由。邏輯上可能有些饒,我們用代碼來解釋一下:線上位址

這裡注意,不能在浏覽器直接打開靜态檔案,需要通過 web 服務,啟動端口去浏覽網址。

這篇文章主要知識點集中在前端路由這塊,能完全看完,并且把實作原理捋一遍,我想你應該對現代前端架構會有一個新的了解。沒有新的了解的同學,來杭州打我,我不還手。

作者:尼克陳

- EOF -

推薦閱讀  點選标題可跳轉

JavaScript閉包和匿名函數的關系詳解

繼續閱讀