vue 單頁應(yīng)用(spa)前端路由實(shí)現(xiàn)原理

寫在前面:通常 SPA 中前端路由有2種實(shí)現(xiàn)方式:

  • window.history
  • location.hash

下面就來介紹下這兩種方式具體怎么實(shí)現(xiàn)的

一.history

1.history基本介紹

window.history 對象包含瀏覽器的歷史,window.history 對象在編寫時可不使用 window 這個前綴然评。history是實(shí)現(xiàn)SPA前端路由是一種主流方法州疾,它有幾個原始方法:

  • history.back() - 與在瀏覽器點(diǎn)擊后退按鈕相同
  • history.forward() - 與在瀏覽器中點(diǎn)擊按鈕向前相同
  • history.go(n) - 接受一個整數(shù)作為參數(shù)踢关,移動到該整數(shù)指定的頁面馋评,比如go(1)相當(dāng)于forward()嫩与,go(-1)相當(dāng)于back()唬涧,go(0)相當(dāng)于刷新當(dāng)前頁面
  • 如果移動的位置超出了訪問歷史的邊界几晤,以上三個方法并不報錯业踏,而是靜默失敗

在HTML5禽炬,history對象提出了 pushState() 方法和 replaceState() 方法,這兩個方法可以用來向歷史棧中添加數(shù)據(jù)勤家,就好像 url 變化了一樣(過去只有 url 變化歷史棧才會變化)腹尖,這樣就可以很好的模擬瀏覽歷史和前進(jìn)后退了,現(xiàn)在的前端路由也是基于這個原理實(shí)現(xiàn)的伐脖。

2.history.pushState

pushState(stateObj, title, url) 方法向歷史棧中寫入數(shù)據(jù)热幔,其第一個參數(shù)是要寫入的數(shù)據(jù)對象(不大于640kB),第二個參數(shù)是頁面的 title, 第三個參數(shù)是 url (相對路徑)讼庇。

  • stateObj :一個與指定網(wǎng)址相關(guān)的狀態(tài)對象绎巨,popstate事件觸發(fā)時,該對象會傳入回調(diào)函數(shù)巫俺。如果不需要這個對象认烁,此處可以填null。
  • title:新頁面的標(biāo)題介汹,但是所有瀏覽器目前都忽略這個值却嗡,因此這里可以填null。
  • url:新的網(wǎng)址嘹承,必須與當(dāng)前頁面處在同一個域窗价。瀏覽器的地址欄將顯示這個網(wǎng)址。

關(guān)于pushState叹卷,有幾個值得注意的地方:

  • pushState方法不會觸發(fā)頁面刷新撼港,只是導(dǎo)致history對象發(fā)生變化坪它,地址欄會有反應(yīng),只有當(dāng)觸發(fā)前進(jìn)后退等事件(back()和forward()等)時瀏覽器才會刷新
  • 這里的 url 是受到同源策略限制的,防止惡意腳本模仿其他網(wǎng)站 url 用來欺騙用戶帝牡,所以當(dāng)違背同源策略時將會報錯

3.history.replaceState

replaceState(stateObj, title, url) 和pushState的區(qū)別就在于它不是寫入而是替換修改瀏覽歷史中當(dāng)前紀(jì)錄往毡,其余和 pushState一模一樣

4.popstate事件

  • 定義:每當(dāng)同一個文檔的瀏覽歷史(即history對象)出現(xiàn)變化時,就會觸發(fā)popstate事件靶溜。
  • 注意:僅僅調(diào)用pushState方法或replaceState方法 开瞭,并不會觸發(fā)該事件,只有用戶點(diǎn)擊瀏覽器倒退按鈕和前進(jìn)按鈕罩息,或者使用JavaScript調(diào)用back嗤详、forward、go方法時才會觸發(fā)瓷炮。另外葱色,該事件只針對同一個文檔,如果瀏覽歷史的切換娘香,導(dǎo)致加載不同的文檔苍狰,該事件也不會觸發(fā)。
  • 用法:使用的時候茅主,可以為popstate事件指定回調(diào)函數(shù)舞痰。這個回調(diào)函數(shù)的參數(shù)是一個event事件對象,它的state屬性指向pushState和replaceState方法為當(dāng)前URL所提供的狀態(tài)對象(即這兩個方法的第一個參數(shù))诀姚。

5.history實(shí)現(xiàn)spa前端路由代碼

<a class="api a">a.html</a>
<a class="api b">b.html</a>
 // 注冊路由
    document.querySelectorAll('.api').forEach(item => {
      item.addEventListener('click', e => {
        e.preventDefault();
        let link = item.textContent;
        if (!!(window.history && history.pushState)) {
          // 支持History API
          window.history.pushState({name: 'api'}, link, link);
        } else {
          // 不支持,可使用一些Polyfill庫來實(shí)現(xiàn)
        }
      }, false)
    });

    // 監(jiān)聽路由
    window.addEventListener('popstate', e => {
      console.log({
        location: location.href,
        state: e.state
      })
    }, false)

popstate監(jiān)聽函數(shù)里打印的e.state便是history.pushState()里傳入的第一個參數(shù),在這里即為{name: 'api'}

二.Hash

1.Hash基本介紹

url 中可以帶有一個 hash
http://localhost:9000/#/a.html

window 對象中有一個事件是 onhashchange玷禽,以下幾種情況都會觸發(fā)這個事件:

  • 直接更改瀏覽器地址赫段,在最后面增加或改變#hash;
  • 通過改變location.href或location.hash的值矢赁;
  • 通過觸發(fā)點(diǎn)擊帶錨點(diǎn)的鏈接糯笙;
  • 瀏覽器前進(jìn)后退可能導(dǎo)致hash的變化,前提是兩個網(wǎng)頁地址中的hash值不同撩银。

2.Hash實(shí)現(xiàn)spa前端路由代碼

    // 注冊路由
    document.querySelectorAll('.api').forEach(item => {
      item.addEventListener('click', e => {
        e.preventDefault();
        let link = item.textContent;
        location.hash = link;
      }, false)
    });

    // 監(jiān)聽路由
    window.addEventListener('hashchange', e => {
      console.log({
        location: location.href,
        hash: location.hash
      })
    }, false)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末给涕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子额获,更是在濱河造成了極大的恐慌够庙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抄邀,死亡現(xiàn)場離奇詭異耘眨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)境肾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門剔难,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胆屿,“玉大人,你說我怎么就攤上這事偶宫》羌#” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵纯趋,是天一觀的道長憎兽。 經(jīng)常有香客問我,道長结闸,這世上最難降的妖魔是什么唇兑? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮桦锄,結(jié)果婚禮上扎附,老公的妹妹穿的比我還像新娘。我一直安慰自己结耀,他們只是感情好留夜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著图甜,像睡著了一般碍粥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上黑毅,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天嚼摩,我揣著相機(jī)與錄音,去河邊找鬼矿瘦。 笑死枕面,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缚去。 我是一名探鬼主播潮秘,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼易结!你這毒婦竟也來了枕荞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤搞动,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體高诺,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了导俘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旅薄。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凯沪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情身笤,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響秤朗,放射性物質(zhì)發(fā)生泄漏取视。R本人自食惡果不足惜作谭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咪奖。 院中可真熱鬧,春花似錦慷垮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饿悬。三九已至,卻和暖如春弟劲,著一層夾襖步出監(jiān)牢的瞬間兔乞,已是汗流浹背霍骄。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工绘沉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喻喳。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓谦去,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蹦哼。 傳聞我的和親對象是個殘疾皇子鳄哭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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