參考來源:
一、vue-router是什麼
vue-router就是WebApp的連結路徑管理系統。vue的單頁面應用是基於路由和元件的,路由用於設定訪問路徑,並將路徑和元件對映起來。傳統的頁面應用,是用一些超連結來實現頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,也就是元件的切換。路由模組的本質 就是建立起url和頁面之間的對映關係。
問題:為什麼不用a標籤
二、vue-router實現原理
1.vue-router 預設 hash 模式
使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新載入。 hash(#)是URL 的錨點,代表的是網頁中的一個位置,單單改變#後的部分,瀏覽器只會滾動到相應位置,不會重新載入網頁,也就是說hash 出現在 URL 中,但不會被包含在 http 請求中,對後端完全沒有影響,因此改變 hash 不會重新載入頁面;同時每一次改變#後的部分,都會在瀏覽器的訪問歷史中增加一個記錄,使用”後退”按鈕,就可以回到上一個位置;所以說Hash模式通過錨點值的改變,根據不同的值,渲染指定DOM位置的不同資料。
問題:是怎麼監聽hash變化的——hashchange()
如何簡單實現:
- 用
Class
關鍵字初始化一個路由.
class Routers {
constructor() {
// 以鍵值對的形式儲存路由
this.routes = {};
// 當前路由的URL
this.currentUrl = '';
}
}
複製程式碼
-
實現路由hash儲存與執行。在初始化完畢後我們需要思考兩個問題:
- 將路由的hash以及對應的callback函式儲存
- 觸發路由hash變化後,執行對應的callback函式
class Routers { constructor() { this.routes = {}; this.currentUrl = ''; } // 將path路徑與對應的callback函式儲存 route(path, callback) { this.routes[path] = callback || function() {}; } // 重新整理 refresh() { // 獲取當前URL中的hash路徑 this.currentUrl = location.hash.slice(1) || '/'; // 執行當前hash路徑的callback函式 this.routes[this.currentUrl](); } } 複製程式碼
-
監聽對應事件,我們只需要在例項化
Class
的時候監聽上面的事件即可.
class Routers {
constructor() {
this.routes = {};
this.currentUrl = '';
this.refresh = this.refresh.bind(this);
window.addEventListener('load', this.refresh, false);
window.addEventListener('hashchange', this.refresh, false);
}
route(path, callback) {
this.routes[path] = callback || function() {};
}
refresh() {
this.currentUrl = location.hash.slice(1) || '/';
this.routes[this.currentUrl]();
}
}
複製程式碼
完整示例:hash router的初步實現
- 此外還要實現回退功能等,hash router完整程式碼參考
2.vue-router
可選擇 history模式
由於hash模式會在url中自帶#,如果不想要很醜的 hash,我們可以用路由的 history 模式,只需要在配置路由規則時,加入"mode: 'history'".
//main.js檔案中
const router = new VueRouter({
mode: 'history',
routes: [...]
})
複製程式碼
這種模式充分利用了html5 history interface 中新增的 pushState() 和 replaceState() 方法。這兩個方法應用於瀏覽器記錄棧,在當前已有的 back、forward、go 基礎之上,它們提供了對歷史記錄修改的功能。只是當它們執行修改時,雖然改變了當前的 URL ,但瀏覽器不會立即向後端傳送請求。不過這種模式要玩好,還需要後臺配置支援。因為我們的應用是個單頁客戶端應用,如果後臺沒有正確的配置,當使用者在瀏覽器直接訪問 outsite.com/user/id 就會返回 404,這就不好看了。所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。
export const routes = [
{path: "/", name: "homeLink", component:Home}
{path: "/register", name: "registerLink", component: Register},
{path: "/login", name: "loginLink", component: Login},
{path: "*", redirect: "/"}]
複製程式碼
2.1.history API
介紹:
其中常用的只有幾種:
window.history.back(); // 後退
window.history.forward(); // 前進
window.history.go(-3); // 後退三個頁面
複製程式碼
history.pushState
用於在瀏覽歷史中新增歷史記錄,但是並不觸發跳轉,此方法接受三個引數,依次為:
state:一個與指定網址相關的狀態物件,popstate事件觸發時,該物件會傳入回撥函式。如果不需要這個物件,此處可以填null。
title:新頁面的標題,但是所有瀏覽器目前都忽略這個值,因此這裡可以填null。
url:新的網址,必須與當前頁面處在同一個域。瀏覽器的位址列將顯示這個網址。
複製程式碼
history.replaceState
方法的引數與pushState
方法一模一樣,區別是它修改瀏覽歷史中當前紀錄,而非新增記錄,同樣不觸發跳轉。
popstate
事件,每當同一個文件的瀏覽歷史(即history物件)出現變化時,就會觸發popstate事件。
2.2.新標準下路由的實現:
class Routers {
constructor() {
this.routes = {};
this._bindPopState();
}
init(path) {
history.replaceState({path: path}, null, path);
this.routes[path] && this.routes[path]();
}
route(path, callback) {
this.routes[path] = callback || function() {};
}
go(path) {
history.pushState({path: path}, null, path);
this.routes[path] && this.routes[path]();
}
_bindPopState() {
window.addEventListener('popstate', e => {
const path = e.state && e.state.path;
this.routes[path] && this.routes[path]();
});
}
}
window.Router = new Routers();
Router.init(location.pathname);
const content = document.querySelector('body');
const ul = document.querySelector('ul');
function changeBgColor(color) {
content.style.backgroundColor = color;
}
Router.route('/', function() {
changeBgColor('yellow');
});
Router.route('/blue', function() {
changeBgColor('blue');
});
Router.route('/green', function() {
changeBgColor('green');
});
ul.addEventListener('click', e => {
if (e.target.tagName === 'A') {
e.preventDefault();
Router.go(e.target.getAttribute('href'));
}
});
複製程式碼
3.使用路由模組來實現頁面跳轉的方式
- 方式1:直接修改位址列
- 方式2:this.$router.push(‘路由地址’)
- 方式3:
<router-link to="路由地址"></router-link>