vue-router 源碼實現(xiàn)前端路由的兩種方式
在學(xué)習(xí) vue-router 的代碼之前,先來簡單了解一下前端路由。
前端路由主要有兩種實現(xiàn)方法:
- Hash 路由
- History 路由
先來看看這兩種方法的實現(xiàn)原理。
接著我們將用它們來簡單實現(xiàn)一個自己的前端路由。
前端路由
Hash 路由
url 的 hash 是以 # 開頭,原本是用來作為錨點,從而定位到頁面的特定區(qū)域。當(dāng) hash 改變時,頁面不會因此刷新,瀏覽器也不會向服務(wù)器發(fā)送請求。
http://www.xxx.com/#/home
同時, hash 改變時,并會觸發(fā)相應(yīng)的 hashchange 事件。所以,hash 很適合被用來做前端路由。當(dāng) hash 路由發(fā)生了跳轉(zhuǎn),便會觸發(fā) hashchange 回調(diào),回調(diào)里可以實現(xiàn)頁面更新的操作,從而達(dá)到跳轉(zhuǎn)頁面的效果。
window.addEventListener('hashchange', function () {
console.log('render');
});
History 路由
HTML5 規(guī)范中提供了 history.pushState 和 history.replaceState 來進(jìn)行路由控制。通過這兩個方法,可以實現(xiàn)改變 url 且不向服務(wù)器發(fā)送請求。同時不會像 hash 有一個 # ,更加的美觀。但是 History 路由需要服務(wù)器的支持,并且需將所有的路由重定向到根頁面。
History 路由的改變不會去觸發(fā)某個事件,所以我們需要去考慮如何觸發(fā)路由更新后的回調(diào)。
有以下兩種方式會改變 url:
- 調(diào)用 history.pushState 或 history.replaceState;
- 點擊瀏覽器的前進(jìn)與后退。
第一個方式可以封裝一個方法,在調(diào)用 pushState(replaceState)后再調(diào)用回調(diào)。
function push (url) {
window.history.pushState({}, null, url);
handleHref();
}
function handleHref () {
console.log('render');
}
第二個方式,瀏覽器的前進(jìn)與后退會觸發(fā) popstate 事件。
window.addEventListener('popstate', handleHref);
路由實現(xiàn)
我們通過 <a> 標(biāo)簽來進(jìn)行切換路由,通過一個 <div> 標(biāo)簽來裝載各路由對應(yīng)的頁面內(nèi)容。
參考 vue-router 的調(diào)用,我們會這么地調(diào)用一個 Router ,將路由與對應(yīng)組件作為參數(shù)傳入:
const router = new Router([
{
path: '/',
component: 'home'
},
{
path: '/book',
component: 'book'
},
{
path: '/movie',
component: 'movie'
}
]);
數(shù)組里是各路由對應(yīng)的要顯示的內(nèi)容,接下來就來開始實現(xiàn)這個 Router 。
Hash 路由實現(xiàn)
Hash 路由 <a> 標(biāo)簽都需要帶上 # :
<div> <a href="#/" rel="external nofollow" >home</a> <a href="#/book" rel="external nofollow" >book</a> <a href="#/movie" rel="external nofollow" >movie</a> <div id="content"></div> </div>
Router 的代碼實現(xiàn)如下:
class Router {
constructor (options) {
this.routes = {};
this.init();
// 遍歷,綁定視圖更新
options.forEach(item => {
this.route(item.path, () => {
document.getElementById('content').innerHTML = item.component;
});
});
}
// 綁定監(jiān)聽事件
init () {
window.addEventListener('load', this.updateView.bind(this), false);
window.addEventListener('hashchange', this.updateView.bind(this), false);
}
// 更新試圖
updateView () {
const currentUrl = window.location.hash.slice(1) || '/';
this.routes[currentUrl] && this.routes[currentUrl]();
}
// 將路由與回調(diào)函數(shù)關(guān)聯(lián)
route (path, cb) {
this.routes[path] = cb;
}
}
實現(xiàn)效果如下:
History 路由實現(xiàn)
History 路由需要服務(wù)器的支持,可以點擊這里 的代碼參考。
<div> <a href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-href="/" rel="external nofollow" >home</a> <a href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-href="/book" rel="external nofollow" >book</a> <a href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-href="/movie" rel="external nofollow" >movie</a> <div id="content"></div> </div>
Router 的代碼實現(xiàn)如下:
class Router {
constructor (options) {
this.routes = {};
this.init();
this.bindEvent();
// 遍歷,綁定視圖更新
options.forEach(item => {
this.route(item.path, () => {
document.getElementById('content').innerHTML = item.component;
});
});
}
// 綁定點擊事件
bindEvent () {
const _this = this;
const links = document.getElementsByTagName('a');
[].forEach.call(links, link => {
link.addEventListener('click', function () {
const url = this.getAttribute('data-href');
_this.push(url);
});
});
}
// 綁定監(jiān)聽事件
init () {
window.addEventListener('load', this.updateView.bind(this), false);
window.addEventListener('popstate', this.updateView.bind(this), false);
}
push (url) {
window.history.pushState({}, null, url);
this.updateView();
}
// 更新試圖
updateView () {
const currentUrl = window.location.pathname || '/';
this.routes[currentUrl] && this.routes[currentUrl]();
}
// 將路由與回調(diào)函數(shù)關(guān)聯(lián)
route (path, cb) {
this.routes[path] = cb;
}
}
實現(xiàn)效果如下:

最后
前端路由實現(xiàn)方式有兩種,分別是:
- Hash 路由
- History 路由
原理都是修改 url 的同時不刷新頁面,不向服務(wù)器發(fā)送請求,通過監(jiān)聽特殊的事件來更新頁面。
以上實現(xiàn)全部源碼參考這里。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue首屏加載過慢出現(xiàn)白屏的6種優(yōu)化方案匯總
vue項目打包上線后,首次打開會發(fā)現(xiàn)加載很慢,出現(xiàn)白屏的問題,下面這篇文章主要給大家介紹了關(guān)于Vue首屏加載過慢出現(xiàn)白屏的6種優(yōu)化方案,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
element實現(xiàn)二級菜單和頂部導(dǎo)航聯(lián)動的示例
本文主要介紹了element實現(xiàn)二級菜單和頂部導(dǎo)航聯(lián)動的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問題
這篇文章主要介紹了Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
通過Vue實現(xiàn)Excel文件的上傳和預(yù)覽功能
在業(yè)務(wù)系統(tǒng)中,Excel 文件作為一種常用的數(shù)據(jù)存儲和傳輸格式,經(jīng)常需要被處理和展示,這篇文章將講解如何通過 Vue 和 xlsx.js 實現(xiàn) Excel 文件的上傳和預(yù)覽功能,需要的朋友可以參考下2025-04-04
詳解vuejs中執(zhí)行npm run dev出現(xiàn)頁面cannot GET/問題
這篇文章主要介紹了詳解vuejs中執(zhí)行npm run dev出現(xiàn)頁面cannot GET/問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
使用Vue創(chuàng)建前后端分離項目的完整過程(前端部分)
這篇文章主要介紹了使用Vue.js和Node.js搭建一個前端和后端分離的項目,并使用VueCLI3腳手架、axios進(jìn)行HTTP請求、Vue-router實現(xiàn)前端路由和vuex進(jìn)行狀態(tài)管理,需要的朋友可以參考下2025-01-01

