1.傳統(tǒng)路由實(shí)現(xiàn)。
window.location.href = 'https://baidu.com' 跳轉(zhuǎn)。刷新頁(yè)面。 history.back()回退。 整個(gè)頁(yè)面重新加載,瀏覽器歷史可以顯示每一個(gè)地址。考慮到安全性但是JS代碼中是無(wú)法操作的。
2.Hash路由方式。
window.href.href = '#hash' localhost:9000#test。并不刷新頁(yè)面。 #后跟的就是頁(yè)面Hash,同樣hash的改變也會(huì)推進(jìn)瀏覽器歷史記錄中。 支持后退前進(jìn)。
window.onhashchange = function () {
? ? console.log('current Hash:',window.location.hash)
}
3.H5 Router。
history.pushState(state, title[, url]) 推進(jìn)路由。增加歷史盞中的一條。 history.replaceState(state,title[, url]) 替換路由。在歷史記錄中替換當(dāng)前記錄。
可以改變網(wǎng)址(存在跨域限制)而不刷新頁(yè)面,這個(gè)強(qiáng)大的特性后來(lái)用到了單頁(yè)面應(yīng)用如:vue-router,react-router-dom中。
僅改變網(wǎng)址,網(wǎng)頁(yè)不會(huì)真的跳轉(zhuǎn),也不會(huì)獲取到新的內(nèi)容,本質(zhì)上網(wǎng)頁(yè)還停留在原頁(yè)面。
狀態(tài)對(duì)象:傳給目標(biāo)路由的信息,可為空
頁(yè)面標(biāo)題:目前所有瀏覽器都不支持,填空字符串即可
可選url:目標(biāo)url,不會(huì)檢查url是否存在,且不能跨域。如不傳該項(xiàng),即給當(dāng)前url添加data
popstate事件會(huì)在點(diǎn)擊后退、前進(jìn)按鈕(或調(diào)用history.back()、history.forward()、history.go()方法)時(shí)觸發(fā)。前提是不能真的發(fā)生了頁(yè)面跳轉(zhuǎn),而是在由history.pushState()或者h(yuǎn)istory.replaceState()形成的歷史節(jié)點(diǎn)中前進(jìn)后退
注意:用history.pushState()或者h(yuǎn)istory.replaceState()不會(huì)觸發(fā)popstate事件。
history.state
當(dāng)前URL下對(duì)應(yīng)的狀態(tài)信息。如果當(dāng)前URL不是通過(guò)pushState或者replaceState產(chǎn)生的,那么history.state是null。history.state可以保存當(dāng)前頁(yè)面的信息,通過(guò)pushState或者replaceState傳遞onpopstate中改變時(shí)候獲得(history.state也可以獲取)。
history.pushState(state, title, url)
state:與要跳轉(zhuǎn)到的URL對(duì)應(yīng)的狀態(tài)信息。
title:不知道干啥用,傳空字符串就行了。
url:要跳轉(zhuǎn)到的URL地址,不能跨域。
將當(dāng)前URL和history.state加入到history中,并用新的state和URL替換當(dāng)前。不會(huì)造成頁(yè)面刷新。
history.replaceState
state:與要跳轉(zhuǎn)到的URL對(duì)應(yīng)的狀態(tài)信息。
title:不知道干啥用,傳空字符串就行了。
url:要跳轉(zhuǎn)到的URL地址,不能跨域。
用新的state和URL替換當(dāng)前。不會(huì)造成頁(yè)面刷新。
window.onpopstate
history.go和history.back(包括用戶按瀏覽器歷史前進(jìn)后退按鈕)觸發(fā),并且頁(yè)面無(wú)刷的時(shí)候(由于使用pushState修改了history)會(huì)觸發(fā)popstate事件,事件發(fā)生時(shí)瀏覽器會(huì)從history中取出URL和對(duì)應(yīng)的state對(duì)象替換當(dāng)前的URL和history.state。通過(guò)event.state也可以獲取history.state。
window.onpopstate = function(event) {
? console.log(event.state); // 當(dāng)前頁(yè)面相關(guān)的history路由信息
? console.log(window.history.state;); // 當(dāng)前頁(yè)面相關(guān)的history路由信息
? console.log(window.location.hash) // hash路徑
? console.log(window.location.pathname) // 絕對(duì)路徑
? console.log(window.location.href) // 全部路徑
};
引入Vue中兩種路由模式的區(qū)別。
Hash模式
hash模式背后的原理是onhashchange事件,可以在window對(duì)象上監(jiān)聽這個(gè)事件:
window.onhashchange = function(event){
? ? // 打印舊的url和新的url
? ? console.log(event.oldURL, event.newURL);
? ? // 相當(dāng)與跳轉(zhuǎn)頁(yè)面的時(shí)候通過(guò)hash區(qū)別頁(yè)面以及傳遞參數(shù)
? ? let hash = location.hash.slice(1);
? ? document.body.style.color = hash;
}
上面的代碼可以通過(guò)改變hash來(lái)改變頁(yè)面字體顏色,雖然沒(méi)什么用,但是一定程度上說(shuō)明了原理。
更關(guān)鍵的一點(diǎn)是,因?yàn)閔ash發(fā)生變化的url都會(huì)被瀏覽器記錄下來(lái),從而你會(huì)發(fā)現(xiàn)瀏覽器的前進(jìn)后退都可以用了,同時(shí)點(diǎn)擊后退時(shí),頁(yè)面字體顏色也會(huì)發(fā)生變化。這樣一來(lái),瀏覽器不會(huì)發(fā)起請(qǐng)求,但是頁(yè)面狀態(tài)和url關(guān)聯(lián)了起來(lái),url改變頁(yè)面可以根據(jù)url進(jìn)行相應(yīng)邏輯變化。這就是hash路由。
History模式
history api,H5的history api給了前端路由充分的自由。相對(duì)于hash路由來(lái)講前端只能控制#后的url地址,而history api允許在同源策略下進(jìn)行任意的自由路由設(shè)置而不刷新頁(yè)面。
需要額外注意:
history api可以分為兩大部分,切換和修改,參考MDN,切換歷史狀態(tài)包括back、forward、go 三個(gè)方法,對(duì)應(yīng)瀏覽器的前進(jìn),后退,跳轉(zhuǎn)操作:
history.go(-2);//后退兩次
history.go(2);//前進(jìn)兩次
history.back(); //后退
hsitory.forward(); //前進(jìn)
修改歷史狀態(tài)包括了pushState,replaceState
兩個(gè)方法,這兩個(gè)方法接收三個(gè)參數(shù):stateObj,title,url
history.pushState({color:'red'}, 'red', 'red')
history.back();
setTimeout(function(){
? ? history.forward();
},0)
window.onpopstate = function(event){
? ? console.log(event.state)
? ? if(event.state && event.state.color === 'red'){
? ? ? ? ? document.body.style.color = 'red';
? ? ? }
}
history模式配置問(wèn)題
vue-router官方文檔:不過(guò)這種模式要玩好,還需要后臺(tái)配置支持。因?yàn)槲覀兊膽?yīng)用是個(gè)單頁(yè)客戶端應(yīng)用,如果后臺(tái)沒(méi)有正確的配置,當(dāng)用戶在瀏覽器直接訪問(wèn)?http://oursite.com/user/id?就會(huì)返回 404,這就不好看了。
只配置前端的情況 首先,我們將mode設(shè)置為history,但不配置后端。然后,假如我們的路由是長(zhǎng)這個(gè)樣子的:
const routes = [
? ? {path: '/home', component: Home},
? ? {path: '/', redirect: '/home'}
];
我們用nginx部署項(xiàng)目,然后在地址欄輸入?http://localhost:8080?(這里配置的端口是8080),你會(huì)發(fā)現(xiàn)地址欄之后會(huì)變?yōu)?a target="_blank">http://localhost:8080/home,?并且看起來(lái)一切正常,似乎路由也可以正常切換而不會(huì)發(fā)生其他問(wèn)題(實(shí)際上會(huì)發(fā)生問(wèn)題,后面會(huì)進(jìn)行討論)。看起來(lái)好像不需要按官網(wǎng)告訴我們的那樣配置后端也能實(shí)現(xiàn)history模式,但如果你直接在地址欄輸入http://localhost:8080/home?,你會(huì)發(fā)現(xiàn)你獲得了一個(gè)404頁(yè)面。
那么http://localhost:8080?為什么可以(部分)正常顯示呢?道理其實(shí)很簡(jiǎn)單,你訪問(wèn)?http://localhost:8080時(shí), 靜態(tài)服務(wù)器(這里是nginx)會(huì)默認(rèn)去目標(biāo)目錄(這里為location中root所指定的目錄)下尋找index.html(這是nginx在端口后沒(méi)有額外路徑時(shí)的默認(rèn)行為),目標(biāo)目錄下有這個(gè)文件嗎?有!然后靜態(tài)服務(wù)器返回給你這個(gè)文件,配合vue-router進(jìn)行轉(zhuǎn)發(fā),自然可以(部分)正常顯示。 但如果直接訪問(wèn)http://localhost:8080/home,?靜態(tài)服務(wù)器會(huì)去目標(biāo)目錄下尋找home文件,目標(biāo)目錄下有這個(gè)文件嗎?沒(méi)有!所以自然就404了。
配置后端
為了達(dá)到直接訪問(wèn)http://localhost:8080/home?也可以成功的目的,我們需要對(duì)后端(這里即nginx)進(jìn)行一些配置。
首先想想,要怎樣才能達(dá)到這個(gè)目的呢?
在傳統(tǒng)的hash模式中?http://localhost:8080#home?,即使不需要配置,靜態(tài)服務(wù)器始終會(huì)去尋找index.html并返回給我們,然后vue-router會(huì)獲取#后面的字符作為參數(shù),對(duì)前端頁(yè)面進(jìn)行變換。
類比一下,在history模式中,我們所想要的情況就是:輸入http://localhost:8080/home, 但最終返回的也是index.html,然后vue-router會(huì)獲取home作為參數(shù),對(duì)前端頁(yè)面進(jìn)行變換。那么在nginx中,誰(shuí)能做到這件事呢?答案就是try_files。
關(guān)于nginx配置以及history模式可能遇到的問(wèn)題可以參考這篇文章Vue Router history模式的配置方法及其原理
Vue對(duì)比兩種模式
??????已經(jīng)有 hash 模式了,而且 hash 能兼容到IE8, history 只能兼容到 IE10,為什么還要搞個(gè) history 呢?
首先,hash 本來(lái)是拿來(lái)做頁(yè)面定位的,如果拿來(lái)做路由的話,原來(lái)的錨點(diǎn)功能就不能用了。其次,hash 的傳參是基于 url 的,如果要傳遞復(fù)雜的數(shù)據(jù),會(huì)有體積的限制,而 history 模式不僅可以在url里放參數(shù),還可以將數(shù)據(jù)存放在一個(gè)特定的對(duì)象中。 最重要的一點(diǎn):
如果不想要很丑的 hash,我們可以用路由的 history 模式 —— 引用自 vueRouter文檔
轉(zhuǎn)載自:https://github.com/19Qingfeng/Router-way