vue-router的hash模式和history模式詳解

前端開膛手發表於2019-04-11
參考來源:
一、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()

如何簡單實現:

  1. Class關鍵字初始化一個路由.
class Routers {
  constructor() {
    // 以鍵值對的形式儲存路由
    this.routes = {};
    // 當前路由的URL
    this.currentUrl = '';
  }
}
複製程式碼
  1. 實現路由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]();
      }
    }
    複製程式碼
  2. 監聽對應事件,我們只需要在例項化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的初步實現

  1. 此外還要實現回退功能等,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介紹:

img

其中常用的只有幾種:

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>

相關文章