您好,登錄后才能下訂單哦!
【造輪子】是筆者學習和理解一些較復雜的代碼結構時的常用方法,它很慢,但是效果卻勝過你讀十幾篇相關的文章。為已知的API方法自行編寫實現,遇到自己無法復現的部分再有針對性地去查資料,最后當你再去學習官方代碼的時候,就會明白這樣做的價值,總有一天,你也將有能力寫出大師級的代碼。
現代前端開發中最流行的頁面模型,莫過于SPA
單頁應用架構。單頁面應用指的是應用只有一個主頁面,通過動態替換DOM內容并同步修改url地址,來模擬多頁應用的效果,切換頁面的功能直接由前臺腳本來完成,而不是由后端渲染完畢后前端只負責顯示。前端三駕馬車Angular
,Vue
,React
均基于此模型來運行的。SPA
能夠以模擬多頁面應用的效果,歸功于其前端路由機制。
前端路由,顧名思義就是一個前端不同頁面的狀態管理器,可以不向后臺發送請求而直接通過前端技術實現多個頁面的效果。angularjs中的
ui-router
,vue中的vue-router
,以及react的react-router
均是對這種功能的具體實現。
既然前端路由
這么牛逼,那必須的好好研究一下。
常見的路由插件中兩種方式都是支持且可以切換的,例如
angularjs1.x
中就可以通過以下代碼從Hash模式切換到H5模式:
$locationProvider.html5Mode(true);
切換到HTML5的路由模式,主要用于避免url地址中包含#而引發的問題。
HTML
頁面中通過錨點定位原理可進行無刷新跳轉,觸發后url地址中會多出# + 'XXX'
的部分,同時在全局的window
對象上觸發hashChange
事件,這樣在頁面錨點哈希改變為某個預設值的時候,通過代碼觸發對應的頁面DOM改變,就可以實現基本的路由了,基于錨點哈希
的路由比較直觀,也是一般前端路由插件中最常用的方式。
下面通過一個實例看一下,當點擊angularjs
的連接時,可以看到控制臺打印出了相應的信息。
HTML5
的History API
為瀏覽器的全局history
對象增加的擴展方法。一般用來解決ajax請求無法通過回退
按鈕回到請求前狀態的問題。
在HTML4中,已經支持window.history
對象來控制頁面歷史記錄跳轉,常用的方法包括:
在HTML5中,window.history
對象得到了擴展,新增的API包括:
瀏覽器訪問一個頁面時,當前地址的狀態信息會被壓入歷史棧
,當調用history.pushState()
方法向歷史棧中壓入一個新的state
后,歷史棧頂部的指針是指向新的state
的。可以將其作用簡單理解為 假裝已經修改了url地址并進行了跳轉 ,除非用戶點擊了瀏覽器的前進
,回退
,或是顯式調用HTML4中的操作歷史棧的方法,否則不會觸發全局的popstate
事件。
在下面的示例中,點擊導航按鈕,可以看到url
地址欄發生了變化,且控制臺打印出了響應的信息。
對比 | hash路由 | History API 路由 |
---|---|---|
url字符串 | 丑 | 正常 |
命名限制 | 通常只能在同一個document 下進行改變 |
url地址可以自己來定義,只要是同一個域名下都可以,自由度更大 |
url地址變更 | 會改變 | 可以改變,也可以不改變 |
狀態保存 | 無內置方法,需要另行保存頁面的狀態信息 | 將頁面信息壓入歷史棧時可以附帶自定義的信息 |
參數傳遞能力 | 受到url總長度的限制, | 將頁面信息壓入歷史棧時可以附帶自定義的信息 |
實用性 | 可直接使用 | 通常服務端需要修改代碼以配合實現 |
兼容性 | IE8以上 | IE10以上 |
造輪子,不是為了把它裝在你的車上,而是當你在荒郊野外開車而輪子出了問題時多一種選擇。
接下來就自己動手實現一個前端路由的插件吧~
myHashRouter.js
我們希望實現的功能是:
MyHashRouter.js
庫when()
方法來定義若干不同的路由狀態init()
方法啟動路由功能首先編寫js骨架,如圖所示:
;(function() {
function Router() {
//記錄路由的跳轉歷史
this.historyStack = [];
//記錄已注冊的路由信息
this.registeredRouter = [];
//路由匹配失敗時跳轉項
this.otherwiseRouter = {
path: '/',
content: 'home page'
}
}
/*
* 啟動路由功能
*/
Router.prototype.init = function() {
}
/*
* 綁定window.onhashchange事件的回調函數
*/
Router.prototype._bindEvents = function() {
}
/**
* 路由注冊方法
*/
Router.prototype.when = function(path, content) {
}
/**
* 判斷新添加的路由是否已存在
*/
Router.prototype._hasThisRouter = function(path) {
}
/**
* 路由不存在時的指定地址
*/
Router.prototype.otherwise = function(path, content) {
}
/**
* 路由跳轉方法,主動調用時可用于跳轉路由
*/
Router.prototype.go = function(topath) {
}
/**
* 用于將對應路由信息渲染至頁面,實現路由切換
*/
Router.prototype.render = function (content) {
}
var router = new Router();
//將接口暴露至全局
window.$router = router;
})();
完成了路由插件的編寫后,我們在demo中引入該庫,然后使用when()
方法注冊幾個路由地址,再使用init()
方法啟動路由,腳本部分代碼如下:
效果:
運行附件中的router-demo-hash.html
,點擊導航按鈕,即可看到url地址欄以及內容區域同步更改。
myHistoryRouter.js
由于History API
不支持低于IE10以下版本的瀏覽器(其他大多數現代瀏覽器基本都支持),所以我們在init()
方法啟動時先進行可用性判斷,基本代碼框架與基于Hash
的路由插件一致。每個方法的實現并不難寫,這里不再贅述,筆者自己的代碼實現放在附件myHashRouter.js
中,水平有限,僅供參考。
為方便理解,本例中將兩種模式分開編寫,如果是插件庫的開發,可以模仿ui-router增加一個html5mode()
的方法,在init()
方法啟動路由時,根據所傳的參數生成不同的路由插件的單例,也就是我們常說的工廠模式來實現即可。
造車輪
是一個很好的學習方式,雖然自己造的車輪很簡陋,但是對于理解工具的底層原理卻很有幫助。myHashRouter.js
的demomyHashRouter.js
的demomyHistoryRouter.js
的demo免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。