前端路由實(shí)現(xiàn)方式
路由需要實(shí)現(xiàn)三個(gè)功能:
- 當(dāng)瀏覽器地址變化時(shí)市咆, 切換頁(yè)面秤掌。
- 點(diǎn)擊瀏覽器后退愁铺、前進(jìn)按鈕,網(wǎng)頁(yè)內(nèi)容跟隨變化闻鉴。
- 刷新瀏覽器茵乱, 網(wǎng)頁(yè)加載當(dāng)前路由對(duì)應(yīng)內(nèi)容。
在單頁(yè)面web網(wǎng)頁(yè)中孟岛,單純的瀏覽器地址改變瓶竭,網(wǎng)頁(yè)不會(huì)重載, 如值改變hash網(wǎng)頁(yè)不會(huì)變化渠羞, 因此路由主要通過監(jiān)聽事件斤贰, 并利用js實(shí)現(xiàn)動(dòng)態(tài)改變網(wǎng)頁(yè)內(nèi)容, 有兩種實(shí)現(xiàn)方式:
- hash模式: 監(jiān)聽瀏覽器地址hash值變化次询, 執(zhí)行響應(yīng)js切換網(wǎng)頁(yè)荧恍。
- history模式: 利用history API實(shí)現(xiàn)url地址改變, 網(wǎng)頁(yè)內(nèi)容改變屯吊。
他們的區(qū)別最明顯的就是 hash API會(huì)在瀏覽器后面增加#
號(hào)送巡, 而history可以自定義地址。
hash模式
使用window.localtion.hash
屬性及窗口的onhashchange
事件盒卸, 可以實(shí)現(xiàn)監(jiān)聽瀏覽器地址hash值變化骗爆, 執(zhí)行相應(yīng)js切換頁(yè)面。
- hash 指的是地址中 #號(hào)以及后面的字符蔽介, 也成為散列值摘投。hash也稱作錨點(diǎn), 本身是用來做頁(yè)面跳轉(zhuǎn)定位的虹蓄。如 http://localhost/index.html#name犀呼,這里的#name就是hash;
- 散列值是不會(huì)隨請(qǐng)求發(fā)送到服務(wù)器端的武花, 所以改變hash不會(huì)重新加載頁(yè)面圆凰。
- 監(jiān)聽 window的
hashchange
事件,當(dāng)hash值發(fā)生變化時(shí)体箕, 可以通過location.hash來獲取和設(shè)置hash值专钉。 - location.hash值的變化會(huì)直接反應(yīng)到瀏覽器地址欄挑童。
觸發(fā)hashchange事件的幾種情況:
- 瀏覽器地址欄hash的變化包括瀏覽器的前進(jìn)、后退跃须,會(huì)觸發(fā)window.location.hash值的變化站叼, 從而觸發(fā)onhashchange事件。
- 當(dāng)訪問http://localhost/index.html#name只會(huì)向服務(wù)器發(fā)送 http://localhost/index.html菇民,請(qǐng)求完畢之后設(shè)置hash為#name, 并觸發(fā)onhashchange事件尽楔。
- 當(dāng)只改變地址欄url 的hash部分, 按下回車第练, 瀏覽器不會(huì)發(fā)送任何請(qǐng)求至服務(wù)器阔馋, 這是只改動(dòng)了hash值并觸發(fā)onhashchange事件。
- html中a標(biāo)簽通過ID定位錨點(diǎn)娇掏, 同時(shí)urL會(huì)自動(dòng)設(shè)置hash呕寝,并觸發(fā)onhashchange事件。
//改變hash
window.location.hash = 'name';
//監(jiān)聽hashchange
window.addEventListener('hashchange', function (e) {
console.log(e);
});
history模式
History對(duì)象主要有兩個(gè)屬性婴梧。
- History.length (當(dāng)前窗口訪問過的網(wǎng)址數(shù)量下梢,包括當(dāng)前網(wǎng)頁(yè))
- History.state (History堆棧最上層的狀態(tài)值)
history.length;
history.state;
方法
-
History,back()
:移動(dòng)到上一個(gè)網(wǎng)址,等同于點(diǎn)擊瀏覽器后退鍵塞蹭。對(duì)于第一個(gè)訪問的網(wǎng)址孽江,該方法無效。 -
History.forward()
: 移動(dòng)到下一個(gè)網(wǎng)站番电, 等同于瀏覽器的后退鍵岗屏。 對(duì)于最后一個(gè)訪問的網(wǎng)址,該方法無效钧舌。
History.go()
: 接受一個(gè)整數(shù)作為參數(shù)担汤, 以當(dāng)前網(wǎng)址為基準(zhǔn)涎跨, 默認(rèn)參數(shù)為0洼冻, 相當(dāng)于刷新頁(yè)面。
history.back();
history.forward();
history.go(1); // 相當(dāng)于history.forward();
histroy.go(-1); //相當(dāng)于history.back();
history.go(0); //刷新當(dāng)前頁(yè)
注意: 移動(dòng)到以前訪問過的頁(yè)面時(shí)隅很, 頁(yè)面通常是從瀏覽器緩中加載撞牢, 而不是重新要求服務(wù)器發(fā)送新的網(wǎng)頁(yè)。
History.pushState()
該方法用于在歷史中添加一條記錄叔营。 pushState()
方法不會(huì)觸發(fā)頁(yè)面刷新屋彪, 只是導(dǎo)致History對(duì)象發(fā)生變化, 地址欄會(huì)有變化绒尊。
語法: history.push(object, title, url);
-
object
: 通過pushState方法可以將該對(duì)象傳遞到新的頁(yè)面中畜挥。 不需要可以填null。 -
title
: 標(biāo)題婴谱, string蟹但,目前幾乎沒有瀏覽器支持該參數(shù)躯泰,,可以填空字符串华糖。 -
url
: 新的網(wǎng)址麦向, 必須與當(dāng)前頁(yè)面處在同一個(gè)域。 如果是跨域網(wǎng)址則會(huì)報(bào)錯(cuò)(這么設(shè)計(jì)是為了防止惡意代碼讓用戶以為他們是在另一個(gè)網(wǎng)站上)客叉。
var data = {name: 'data'};
history.pushState(data,' ','/open');
console.log(history.state);// {name: 'data'}
注意: 如果pushState的url參數(shù)設(shè)置了一個(gè)新的hash诵竭, 并不會(huì)觸發(fā)hashchange事件。反過來兼搏, 如果url的hash變動(dòng)了卵慰,則會(huì)在History對(duì)象創(chuàng)建一條瀏覽記錄。
HIstory.replaceState()
該方法用來修改History對(duì)象的當(dāng)前記錄佛呻, 用法與pushState()方法一樣
history.pushState({a: 1}, ' ', '?a=1');
//url為 https://www.baidu.com?a=1
history.pushState({a: 2}, ' ', '?a=2');
//url為 https://www.baidu.com?a=2
history.pushState({a: 3}, ' ', '?a=3');
//url為 https://www.baidu.com?a=3
history.back();
//url為 https://www.baidu.com?a=1
history.back();
//url為 https://www.baidu.com
history.go(2);
//url為 https://www.baidu.com?a=3
popstate事件
每當(dāng)history度歘愛能出現(xiàn)變化時(shí)呵燕, 就會(huì)觸發(fā)popstate事件。
- 僅僅調(diào)用
pushState()
或replaceState()
方法件相, 并不會(huì)觸發(fā)popstate事件再扭。 - 只有點(diǎn)擊瀏覽器前進(jìn)倒退按鈕,或者使用js調(diào)用
history,back(),history.forward(),history.go()
方法時(shí)才會(huì)觸發(fā)夜矗。 - popstate事件只針對(duì)同一個(gè)文檔泛范, 如果瀏覽歷史的切換, 導(dǎo)致加載不同的文檔紊撕, 該事件也不會(huì)觸發(fā)罢荡。
- 頁(yè)面第一次加載的時(shí)候, 瀏覽器不會(huì)觸發(fā)
popstate
事件对扶。
window.addEventListener('popstate',function(e) {
var s1 = e.state;
var s2 = history.state;
// s1 == s2
});
history致命的缺點(diǎn)是當(dāng)改變頁(yè)面地址后区赵,強(qiáng)制刷新瀏覽器時(shí), 如果后端沒有對(duì)應(yīng)的地址浪南,會(huì)404笼才,因?yàn)樗⑿率悄卯?dāng)前地址去請(qǐng)求服務(wù)器, 如果服務(wù)器沒有相應(yīng)的響應(yīng)络凿,頁(yè)面則會(huì)404骡送。