扒一扒路由的演變過(guò)程

路由

1. 從前的請(qǐng)求 —— 服務(wù)端渲染(SSR:Server Side Render)

在最開始施禾,在瀏覽器中向服務(wù)端發(fā)送一個(gè)請(qǐng)求召锈,服務(wù)端會(huì)把 html 字符串生成好,再發(fā)送給客戶端识颊,客戶端直接渲染即可。

并不是說(shuō)一個(gè) html 就只請(qǐng)求了一次服務(wù)端。一個(gè) html 里可能會(huì)引用一些 js、css 文件,這些靜態(tài)資源都是放在服務(wù)端的。當(dāng)瀏覽器渲染服務(wù)端返回的 html 字符串小作,讀到諸如
<script src="js/jquery.js"></script> 時(shí)會(huì)再次向服務(wù)端發(fā)送一條請(qǐng)求去獲取 jquery.js 資源的,獲取回來(lái)之后在瀏覽器中加載一遍稼钩。

缺點(diǎn):在后管系統(tǒng)中顾稀,當(dāng)從“用戶管理”菜單跳轉(zhuǎn)到“角色管理”菜單時(shí),往往變化的只是表格的字段以及數(shù)據(jù)坝撑,但在服務(wù)端渲染中每次都需要全部請(qǐng)求一遍静秆。請(qǐng)求頭部橫條,請(qǐng)求左側(cè)菜單欄巡李,重新加載 jquery.js 等等抚笔。我們希望不需要改變的東東就別動(dòng)了,修改變局部侨拦。

2. Ajax 出現(xiàn)實(shí)現(xiàn)局部刷新

ajax 的出現(xiàn)解決了上面每次請(qǐng)求頁(yè)面都全部刷新的問(wèn)題殊橙,只是請(qǐng)求數(shù)據(jù),然后通過(guò) Dom 操作修改 html 中表格相關(guān)的東東狱从。

缺點(diǎn):使用 ajax 異步請(qǐng)求之后膨蛮,點(diǎn)擊瀏覽器的回退上一個(gè)頁(yè)面會(huì)發(fā)現(xiàn)沒效果,因?yàn)檫@次請(qǐng)求僅僅是數(shù)據(jù)的請(qǐng)求季研,并沒有重新刷新頁(yè)面敞葛,也就沒有加入到瀏覽器歷史棧中。

3. 單頁(yè)應(yīng)用(SPA:Single Pagination Application)

單頁(yè)應(yīng)用的出現(xiàn)解決了服務(wù)端渲染和 ajax 存在的問(wèn)題训貌。

解決服務(wù)端渲染的問(wèn)題:

人們開始想,從“用戶管理”菜單跳轉(zhuǎn)到“角色管理”菜單時(shí),需要請(qǐng)求服務(wù)端獲取 html 之后在瀏覽器中渲染递沪。這個(gè)渲染的過(guò)程包括創(chuàng)建一個(gè)個(gè) dom 元素豺鼻,如 div dom 元素,p dom 元素款慨。他們會(huì)認(rèn)為這一過(guò)程很消耗性能儒飒,事實(shí)也是如此,可以試著在瀏覽器調(diào)試臺(tái)中輸入:document.createElement('div') 會(huì)發(fā)現(xiàn)僅僅創(chuàng)建一個(gè) div 元素附帶創(chuàng)建了很多屬性和方法檩奠,那些東東你可能壓根就用不上桩了。

單頁(yè)應(yīng)用的解決方式是,在頁(yè)面第一次加載的時(shí)候就把“用戶管理”的表格 dom 元素和“角色管理”的表格 dom 元素都加載進(jìn)來(lái)埠戳,當(dāng)再次從“用戶管理”切換到“角色管理”時(shí)井誉,只需要渲染
“角色管理” 的表格 dom,而不是像服務(wù)端渲染那樣將整個(gè)頁(yè)面都渲染一遍整胃,渲染的少了颗圣,性能上無(wú)疑得到了提升。這一點(diǎn)和 ajax 有點(diǎn)相似屁使。

單頁(yè)應(yīng)用與 ajax 的區(qū)別:
ajax 是先請(qǐng)求數(shù)據(jù)在岂,然后在瀏覽器通過(guò) js 創(chuàng)建 dom 進(jìn)行替換。單頁(yè)應(yīng)用在第一次加載應(yīng)用的時(shí)候?qū)?dom 都加載到瀏覽器中蛮寂,只不過(guò)先用了“用戶管理”表格 dom蔽午,“角色管理”表格 dom 也加載進(jìn)來(lái)了,放在那暫時(shí)不用酬蹋。這種通過(guò)點(diǎn)擊不同菜單及老,自動(dòng)替換不同的 dom 的方式就叫做路由。

還有一點(diǎn)區(qū)別就是單頁(yè)應(yīng)用解決了 ajax 的問(wèn)題:?jiǎn)雾?yè)應(yīng)用通過(guò) hashHistory 和 browerHistory 可以將每次的路由都加入到瀏覽器的歷史棧除嘹,這樣點(diǎn)擊回退按鈕就可以回到上一個(gè)頁(yè)面写半。
說(shuō)起來(lái) ajax 也可以通過(guò) hashHistory 和 browerHistory 將路由添加到歷史棧,只不過(guò)歷史大環(huán)境下決定它還是功能專一點(diǎn)尉咕。

當(dāng)然叠蝇,單頁(yè)應(yīng)用也有個(gè)大問(wèn)題,那就是首次加載時(shí)間很長(zhǎng)年缎,造成頁(yè)面出現(xiàn)白屏悔捶。單頁(yè)應(yīng)用第一次加載時(shí)就會(huì)取請(qǐng)求服務(wù)端獲取所有 html 和 js,然后接下來(lái)的操作都在瀏覽器端進(jìn)行了单芜,
瀏覽器會(huì)去渲染這些文件蜕该,但由于東東太多了,在瀏覽器端會(huì)出現(xiàn)短暫白屏的現(xiàn)象洲鸠。
為什么服務(wù)端渲染不會(huì)有白屏現(xiàn)象:因?yàn)榉?wù)端只會(huì)返回 html字符串堂淡,瀏覽器只要渲染一下即可馋缅,渲染的東西少了,自然就快了绢淀。

4. 路由的概念

去銀行辦理業(yè)務(wù)萤悴,銀行小姐姐會(huì)詢問(wèn)你辦理什么業(yè)務(wù),然后教你不同的操作皆的。有一張表:

業(yè)務(wù) 操作
辦理銀行卡 先做xx覆履,再做xx
辦理網(wǎng)上銀行業(yè)務(wù) 先做yy,再做yy

去上廁所费薄,如果你是女生硝全,就進(jìn)入女廁所,你是男生楞抡,就進(jìn)入男廁所伟众。有一張表:

性別 廁所
男生 男廁所
女生 女廁所

你去你女朋友宿舍樓下找她,你告訴宿管大媽你女朋友是xx專業(yè)xx班的學(xué)生拌倍,宿管大媽告訴你去幾樓幾零幾赂鲤。有一張表:

姓名 宿舍
張曉麗 503 宿舍
李美麗 301 宿舍

回到瀏覽器路由,在瀏覽器中輸入“l(fā)ocalost:8000/”會(huì)顯示首頁(yè)柱恤,輸入“l(fā)ocalost:8000/user”會(huì)顯示用戶頁(yè)面数初,輸入“l(fā)ocalost:8000/role”會(huì)顯示角色頁(yè)面。有一張表:

路由 視圖
/ 首頁(yè)
/user 用戶頁(yè)面
/role 角色頁(yè)面

在瀏覽器中路由的作用就是根據(jù)你的輸入的地址梗顺,顯示不同的視圖泡孩。那就意味著首先要定義這樣一張路由表。

5. 路由/單頁(yè)應(yīng)用的實(shí)現(xiàn)原理

了解了路由表寺谤,好奇寶寶肯定想知道具體如何實(shí)現(xiàn)呢仑鸥?

單頁(yè)應(yīng)用路由的實(shí)現(xiàn)分為兩個(gè)步驟:改變?yōu)g覽器地址欄地址,視圖切換变屁。

1)HashHistory 的應(yīng)用

  • 改變?yōu)g覽器地址欄地址
    window.location.hash = 'bbbb' 瀏覽器地址會(huì)變成 localhost:8080/#bbbb
    window.location 對(duì)象專門處理瀏覽器地址欄各種操作眼俊。
    使用 window.location.hash 操作時(shí),已經(jīng)將路由 '#bbbb' 添加到了瀏覽器歷史棧中粟关,點(diǎn)擊回退按鈕可以回退到上一個(gè)頁(yè)面疮胖。
  • 添加瀏覽器事件監(jiān)聽函數(shù)
    window.addEventListener('hashchange', function () {})
    此時(shí)如果 hash 變化了,就會(huì)觸發(fā)該事件闷板,在這個(gè)事件里就可以實(shí)現(xiàn)替換局部 dom 的實(shí)現(xiàn)了澎灸。

2)Browser History (h5 history)的出現(xiàn)
使用 HashHistory 產(chǎn)生的路由 localhost:8080/#bbbb 會(huì)有個(gè)井號(hào) #,很多人認(rèn)為這很不美觀遮晚,但一直也無(wú)計(jì)可施性昭,直到 h5 的出現(xiàn),帶來(lái)了新的 API —— window.history 的更新县遣。

  • 改變?yōu)g覽器的地址欄地址
    var stateObj = { foo: "bar" };
    history.pushState(stateObj, "page 2", "user");
    可以看到路由變成了 localhost:8000/user糜颠,沒有了那不美觀的 #汹族。關(guān)于history api 具體用法,參考:http://blog.csdn.net/tianyitianyi1/article/details/user
  • 添加瀏覽器事件監(jiān)聽函數(shù)
    通過(guò) history api 改變?yōu)g覽器地址欄地址同樣會(huì)觸發(fā)一個(gè)事件
    window.onpopstate = function () { }

3)手寫 js 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的路由功能:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hash</title>
</head>
<body>
        <ul class="cs">
            <li class="li">
                <a href="#/" class="button button-primary">首頁(yè)</a>
            </li>
            <li class="li">
                <a href="#/nav" class="button button-highlight">菜單</a>
            </li>
            <li class="li">
                <a href="#/subpage" class="button button-royal">子頁(yè)</a>
            </li>
        </ul>
        <div id="app" style="border:2px solid #f00;height:30px;">
                Hello
        </div>
<script>
function Router(){
    //有個(gè)名字其兴,用做一件事情
    this.routes = [];
    this.currentUrl = "";
    this.init();//先讓他初始化監(jiān)聽事件鞠抑,然后才調(diào)用路由
}

Router.prototype = {
    constructor:Router,
    router:function(path,callback){
        this.routes[path] = callback || function(){};
    },
    refresh:function(){
        this.currentUrl = location.hash.slice(1) || '/';
        this.routes[this.currentUrl]();//通過(guò)路由名字去調(diào)用相對(duì)應(yīng)的方法
    },
    init:function(){//監(jiān)聽頁(yè)面:加載的時(shí)候、監(jiān)聽改變的時(shí)候
        window.addEventListener("load",this.refresh.bind(this),false);
        window.addEventListener("hashchange",this.refresh.bind(this),false);
    }
}

var appObj = document.getElementById("app");
function changeText(text){
    appObj.innerHTML = text;
}

var router = new Router();

router.router("/",function(){
    changeText("首頁(yè)");
});
router.router("/nav",function(){
    changeText("菜單");
});
router.router("/subpage",function(){
    changeText("子頁(yè)");
});
</script>
</body>
</html>

6. 最終

目前由于單頁(yè)應(yīng)用操作起來(lái)更快速忌警,除了首屏加載尷尬的問(wèn)題,人們提出的方案是使用服務(wù)端渲染首屏秒梳,之后其它操作都進(jìn)行單頁(yè)應(yīng)用的操作來(lái)規(guī)避首屏加載的問(wèn)題法绵。

最終,當(dāng)硬件與軟件發(fā)展到一定程度酪碘,網(wǎng)速加速到一定程度朋譬,單頁(yè)應(yīng)用首屏加載雖然需要請(qǐng)求很多東東,但由于網(wǎng)速的變快一瞬間就加載下來(lái)兴垦,服務(wù)端渲染可能就會(huì)慢慢退出歷史舞臺(tái)徙赢,這也是一種技術(shù)的發(fā)展趨勢(shì)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末探越,一起剝皮案震驚了整個(gè)濱河市狡赐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钦幔,老刑警劉巖枕屉,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鲤氢,居然都是意外死亡搀擂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門卷玉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哨颂,“玉大人,你說(shuō)我怎么就攤上這事相种⊥眨” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵蚂子,是天一觀的道長(zhǎng)沃测。 經(jīng)常有香客問(wèn)我,道長(zhǎng)食茎,這世上最難降的妖魔是什么蒂破? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮别渔,結(jié)果婚禮上附迷,老公的妹妹穿的比我還像新娘惧互。我一直安慰自己,他們只是感情好喇伯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布喊儡。 她就那樣靜靜地躺著,像睡著了一般稻据。 火紅的嫁衣襯著肌膚如雪艾猜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天捻悯,我揣著相機(jī)與錄音匆赃,去河邊找鬼。 笑死今缚,一個(gè)胖子當(dāng)著我的面吹牛算柳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姓言,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼瞬项,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了何荚?” 一聲冷哼從身側(cè)響起囱淋,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎餐塘,沒想到半個(gè)月后绎橘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唠倦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年称鳞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稠鼻。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冈止,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出候齿,到底是詐尸還是另有隱情熙暴,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布慌盯,位于F島的核電站周霉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏亚皂。R本人自食惡果不足惜俱箱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灭必。 院中可真熱鬧狞谱,春花似錦乃摹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至伶跷,卻和暖如春掰读,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叭莫。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工磷支, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人食寡。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像廓潜,于是被迫代替她去往敵國(guó)和親抵皱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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

  • 問(wèn)答題47 /72 常見瀏覽器兼容性問(wèn)題與解決方案辩蛋? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理呻畸,服務(wù)發(fā)現(xiàn),斷路器悼院,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評(píng)論 25 707
  • 啦啦啦啦啦~ 本精釀小白又入了一波小酒∠( ? 」∠)_ 夏天回到家有冰箱 就等于有了酒的圣地ヾ(′?`)? 左一...
    平和島蹭閱讀 526評(píng)論 0 3
  • "現(xiàn)在的小孩都毛毛躁躁的嗎。呵呵呵……"伴隨著一陣爽朗的笑聲据途,從山洞里走出來(lái)一位老人绞愚,我們都不知所措。這時(shí)颖医,雷蒙走...
    古天問(wèn)閱讀 249評(píng)論 1 1