溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

javascript基礎(chǔ)修煉(6)——前端路由的基本原理

發(fā)布時(shí)間:2020-06-19 05:43:41 來(lái)源:網(wǎng)絡(luò) 閱讀:1364 作者:大史不說(shuō)話 欄目:開(kāi)發(fā)技術(shù)

javascript基礎(chǔ)修煉(6)——前端路由的基本原理

【造輪子】是筆者學(xué)習(xí)和理解一些較復(fù)雜的代碼結(jié)構(gòu)時(shí)的常用方法,它很慢,但是效果卻勝過(guò)你讀十幾篇相關(guān)的文章。為已知的API方法自行編寫(xiě)實(shí)現(xiàn),遇到自己無(wú)法復(fù)現(xiàn)的部分再有針對(duì)性地去查資料,最后當(dāng)你再去學(xué)習(xí)官方代碼的時(shí)候,就會(huì)明白這樣做的價(jià)值,總有一天,你也將有能力寫(xiě)出大師級(jí)的代碼。

一. 前端路由

現(xiàn)代前端開(kāi)發(fā)中最流行的頁(yè)面模型,莫過(guò)于SPA單頁(yè)應(yīng)用架構(gòu)。單頁(yè)面應(yīng)用指的是應(yīng)用只有一個(gè)主頁(yè)面,通過(guò)動(dòng)態(tài)替換DOM內(nèi)容并同步修改url地址,來(lái)模擬多頁(yè)應(yīng)用的效果,切換頁(yè)面的功能直接由前臺(tái)腳本來(lái)完成,而不是由后端渲染完畢后前端只負(fù)責(zé)顯示。前端三駕馬車(chē)Angular,Vue,React均基于此模型來(lái)運(yùn)行的。SPA能夠以模擬多頁(yè)面應(yīng)用的效果,歸功于其前端路由機(jī)制。

前端路由,顧名思義就是一個(gè)前端不同頁(yè)面的狀態(tài)管理器,可以不向后臺(tái)發(fā)送請(qǐng)求而直接通過(guò)前端技術(shù)實(shí)現(xiàn)多個(gè)頁(yè)面的效果。angularjs中的ui-router,vue中的vue-router,以及react的react-router均是對(duì)這種功能的具體實(shí)現(xiàn)。

既然前端路由這么牛逼,那必須的好好研究一下。

二. 兩種實(shí)現(xiàn)方式及其原理

常見(jiàn)的路由插件中兩種方式都是支持且可以切換的,例如angularjs1.x中就可以通過(guò)以下代碼從Hash模式切換到H5模式:
$locationProvider.html5Mode(true);
切換到HTML5的路由模式,主要用于避免url地址中包含#而引發(fā)的問(wèn)題。

1.HashChange

1.1 原理

HTML頁(yè)面中通過(guò)錨點(diǎn)定位原理可進(jìn)行無(wú)刷新跳轉(zhuǎn),觸發(fā)后url地址中會(huì)多出# + 'XXX'的部分,同時(shí)在全局的window對(duì)象上觸發(fā)hashChange事件,這樣在頁(yè)面錨點(diǎn)哈希改變?yōu)槟硞€(gè)預(yù)設(shè)值的時(shí)候,通過(guò)代碼觸發(fā)對(duì)應(yīng)的頁(yè)面DOM改變,就可以實(shí)現(xiàn)基本的路由了,基于錨點(diǎn)哈希的路由比較直觀,也是一般前端路由插件中最常用的方式。

1.2 應(yīng)用

下面通過(guò)一個(gè)實(shí)例看一下,當(dāng)點(diǎn)擊angularjs的連接時(shí),可以看到控制臺(tái)打印出了相應(yīng)的信息。
javascript基礎(chǔ)修煉(6)——前端路由的基本原理
javascript基礎(chǔ)修煉(6)——前端路由的基本原理

2.HTML5 HistoryAPI

2.1 原理

HTML5History API為瀏覽器的全局history對(duì)象增加的擴(kuò)展方法。一般用來(lái)解決ajax請(qǐng)求無(wú)法通過(guò)回退按鈕回到請(qǐng)求前狀態(tài)的問(wèn)題

在HTML4中,已經(jīng)支持window.history對(duì)象來(lái)控制頁(yè)面歷史記錄跳轉(zhuǎn),常用的方法包括:

  • history.forward(); //在歷史記錄中前進(jìn)一步
  • history.back(); //在歷史記錄中后退一步
  • history.go(n): //在歷史記錄中跳轉(zhuǎn)n步驟,n=0為刷新本頁(yè),n=-1為后退一頁(yè)。

在HTML5中,window.history對(duì)象得到了擴(kuò)展,新增的API包括:

  • history.pushState(data[,title][,url]);//向歷史記錄中追加一條記錄
  • history.replaceState(data[,title][,url]);//替換當(dāng)前頁(yè)在歷史記錄中的信息。
  • history.state;//是一個(gè)屬性,可以得到當(dāng)前頁(yè)的state信息。
  • window.onpopstate;//是一個(gè)事件,在點(diǎn)擊瀏覽器后退按鈕或js調(diào)用forward()、back()、go()時(shí)觸發(fā)。監(jiān)聽(tīng)函數(shù)中可傳入一個(gè)event對(duì)象,event.state即為通過(guò)pushState()或replaceState()方法傳入的data參數(shù)。
2.2 應(yīng)用

瀏覽器訪問(wèn)一個(gè)頁(yè)面時(shí),當(dāng)前地址的狀態(tài)信息會(huì)被壓入歷史棧,當(dāng)調(diào)用history.pushState()方法向歷史棧中壓入一個(gè)新的state后,歷史棧頂部的指針是指向新的state的。可以將其作用簡(jiǎn)單理解為 假裝已經(jīng)修改了url地址并進(jìn)行了跳轉(zhuǎn) ,除非用戶點(diǎn)擊了瀏覽器的前進(jìn),回退,或是顯式調(diào)用HTML4中的操作歷史棧的方法,否則不會(huì)觸發(fā)全局的popstate事件。

在下面的示例中,點(diǎn)擊導(dǎo)航按鈕,可以看到url地址欄發(fā)生了變化,且控制臺(tái)打印出了響應(yīng)的信息。
javascript基礎(chǔ)修煉(6)——前端路由的基本原理
javascript基礎(chǔ)修煉(6)——前端路由的基本原理

3.hash 和 history API對(duì)比

對(duì)比 hash路由 History API 路由
url字符串 正常
命名限制 通常只能在同一個(gè)document下進(jìn)行改變 url地址可以自己來(lái)定義,只要是同一個(gè)域名下都可以,自由度更大
url地址變更 會(huì)改變 可以改變,也可以不改變
狀態(tài)保存 無(wú)內(nèi)置方法,需要另行保存頁(yè)面的狀態(tài)信息 將頁(yè)面信息壓入歷史棧時(shí)可以附帶自定義的信息
參數(shù)傳遞能力 受到url總長(zhǎng)度的限制, 將頁(yè)面信息壓入歷史棧時(shí)可以附帶自定義的信息
實(shí)用性 可直接使用 通常服務(wù)端需要修改代碼以配合實(shí)現(xiàn)
兼容性 IE8以上 IE10以上

三.親手造一個(gè)簡(jiǎn)單的前端路由插件

造輪子,不是為了把它裝在你的車(chē)上,而是當(dāng)你在荒郊野外開(kāi)車(chē)而輪子出了問(wèn)題時(shí)多一種選擇。

接下來(lái)就自己動(dòng)手實(shí)現(xiàn)一個(gè)前端路由的插件吧~

3.1基于Hash的前端路由插件myHashRouter.js

我們希望實(shí)現(xiàn)的功能是:

  • 1.引入MyHashRouter.js庫(kù)
  • 2.通過(guò)when()方法來(lái)定義若干不同的路由狀態(tài)
  • 3.通過(guò)init()方法啟動(dòng)路由功能
  • 4.通過(guò)點(diǎn)擊導(dǎo)航實(shí)現(xiàn)前端路由切換

首先編寫(xiě)js骨架,如圖所示:

;(function() {
    function Router() {
        //記錄路由的跳轉(zhuǎn)歷史
        this.historyStack = [];
        //記錄已注冊(cè)的路由信息
        this.registeredRouter = [];
        //路由匹配失敗時(shí)跳轉(zhuǎn)項(xiàng)
        this.otherwiseRouter = {
            path: '/',
            content: 'home page'
        }
    }

    /*
     * 啟動(dòng)路由功能
     */
    Router.prototype.init = function() {

    }

     /*
     * 綁定window.onhashchange事件的回調(diào)函數(shù)
     */
    Router.prototype._bindEvents = function() {

    }

    /**
     * 路由注冊(cè)方法
     */
    Router.prototype.when = function(path, content) {

    }

    /**
     * 判斷新添加的路由是否已存在
     */
    Router.prototype._hasThisRouter = function(path) {

    }

    /**
     * 路由不存在時(shí)的指定地址
     */
    Router.prototype.otherwise = function(path, content) {

    }

    /**
     * 路由跳轉(zhuǎn)方法,主動(dòng)調(diào)用時(shí)可用于跳轉(zhuǎn)路由
     */
    Router.prototype.go = function(topath) {

    }

    /**
     * 用于將對(duì)應(yīng)路由信息渲染至頁(yè)面,實(shí)現(xiàn)路由切換
     */
    Router.prototype.render = function (content) {

    }

    var router = new Router();

    //將接口暴露至全局
    window.$router = router;
})();

完成了路由插件的編寫(xiě)后,我們?cè)赿emo中引入該庫(kù),然后使用when()方法注冊(cè)幾個(gè)路由地址,再使用init()方法啟動(dòng)路由,腳本部分代碼如下:
javascript基礎(chǔ)修煉(6)——前端路由的基本原理

效果:
運(yùn)行附件中的router-demo-hash.html,點(diǎn)擊導(dǎo)航按鈕,即可看到url地址欄以及內(nèi)容區(qū)域同步更改。
javascript基礎(chǔ)修煉(6)——前端路由的基本原理

3.2基于History API的前端路由插件myHistoryRouter.js

由于History API不支持低于IE10以下版本的瀏覽器(其他大多數(shù)現(xiàn)代瀏覽器基本都支持),所以我們?cè)?code>init()方法啟動(dòng)時(shí)先進(jìn)行可用性判斷,基本代碼框架與基于Hash的路由插件一致。每個(gè)方法的實(shí)現(xiàn)并不難寫(xiě),這里不再贅述,筆者自己的代碼實(shí)現(xiàn)放在附件myHashRouter.js中,水平有限,僅供參考。
javascript基礎(chǔ)修煉(6)——前端路由的基本原理

3.3集成說(shuō)明

為方便理解,本例中將兩種模式分開(kāi)編寫(xiě),如果是插件庫(kù)的開(kāi)發(fā),可以模仿ui-router增加一個(gè)html5mode()的方法,在init()方法啟動(dòng)路由時(shí),根據(jù)所傳的參數(shù)生成不同的路由插件的單例,也就是我們常說(shuō)的工廠模式來(lái)實(shí)現(xiàn)即可。

四.后記

  • 造車(chē)輪是一個(gè)很好的學(xué)習(xí)方式,雖然自己造的車(chē)輪很簡(jiǎn)陋,但是對(duì)于理解工具的底層原理卻很有幫助。
  • 本例只是編寫(xiě)了一個(gè)路由工具的基本骨架,真正的路由工具還需要做很多功能擴(kuò)展,個(gè)別功能的復(fù)雜度也會(huì)很高,例如路徑的正則匹配,懶加載,組合視圖,嵌套視圖,路由動(dòng)畫(huà)等等,有興趣的小伙伴可以在本例提供的框架上進(jìn)行學(xué)習(xí)擴(kuò)展。
  • 附件說(shuō)明:
    • index_h6history.html —— history API基本用法演示demo
    • index_hashchange.html —— hashchange基本用法演示demo
    • router-demo-hash.html —— 引用了myHashRouter.js的demo
    • myHashRouter.js —— 自己開(kāi)發(fā)的基于hash簡(jiǎn)易路由插件
    • router-demo-hash.html —— 引用了myHashRouter.js的demo
    • myHistoryRouter.js —— 自己開(kāi)發(fā)的基于historyAPI的簡(jiǎn)易路由插件
    • router-demo-history.html —— 引用了myHistoryRouter.js的demo
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI