前端路由探究--Hash模式與History模式

什麼是SPA

singel page web application 單頁WEB應用。只有一個 HTML 頁面,利用 JS 動態的變換 HTML 的內容,從而來模擬多個視圖間跳轉。只有一個完整的頁面;它在加載頁面時,不會加載整個頁面,而是隻更新某個指定的容器中內容。單頁面應用(SPA)的核心之一是: 更新視圖而不從新請求頁面前端

SPA缺點

1.沒法記住用戶的操做記錄 2.只有一個url,對SEO不友好。web

什麼是前端路由

就是在保證只有一個 HTML 頁面,且與用戶交互時不刷新和跳轉頁面的同時,爲 SPA 中的每一個視圖展現形式匹配一個特殊的 url。在刷新、前進、後退和SEO時均經過這個特殊的 url 來實現。api

  1. 能夠改變url可是不會向服務器發送請求 2.能夠監聽到url的變化

hash模式

hash是指url中#號以及後面的字符,如 "www.baidu.com/#hashhash"。其中 "#hashhash" 就是咱們指望的 hash 值。瀏覽器

hash值的改變不會致使瀏覽器向服務器發送請求,可是hash值的變化會觸發hashChange事件,瀏覽器的前進後退也能對其進行控制。bash

window.location.hash = 'hash字符串'; // 用於設置 hashlet hash = window.location.hash; // 獲取當前 hash 值

// 監聽hash變化,點擊瀏覽器的前進後退會觸發
window.addEventListener('hashchange', function(event){ 
    let newURL = event.newURL; // hash 改變後的新 url
    let oldURL = event.oldURL; // hash 改變前的舊 url
},false)

hash路由的實現
class HashRouter{
    constructor(){
        //用於存儲不一樣hash值對應的回調函數
        this.routers = {};
        window.addEventListener('hashchange',this.load.bind(this),false)
    }
    //用於註冊每一個視圖
    register(hash,callback = function(){}){
        this.routers[hash] = callback;
    }
    //用於註冊首頁
    registerIndex(callback = function(){}){
        this.routers['index'] = callback;
    }
    //根據不一樣的hash調用不一樣視圖的回調函數
    load(){
        let hash = location.hash.slice(1),
            handler;
        //沒有hash 默認爲首頁
        if(!hash){
            handler = this.routers.index;
        }else{
            handler = this.routers[hash];
        }
        //執行註冊的回調函數
        handler.call(this);
    }
}
複製代碼

思路:服務器

  1. 建立一個hashRouter的類,裏面封裝了hash路由的操做
  2. 這個類中有一個註冊函數,傳入hash和回調函數,能夠爲不一樣的hash綁定不一樣的回調
  3. 在SPA中註冊hash值和回調函數。點擊a標籤會觸發hashchange事件。監聽hashchange事件,第二個參數綁定一個函數。這個函數根據不一樣的hash值調用註冊路由時綁定的回調函數。

history模式

早期的history對象只能用於多頁面跳轉 三個api (go,back,forward) HTML5中新增了pushState(obj,null,url),replaceState(obj,null,url)API history.pushState() 和 history.replaceState() 能夠改變 url 同時,不會刷新頁面app

//history實現
class HistoryRouter{
    constructor(){
        //用於存儲不一樣path值對應的回調函數
        this.routers = {};
        this.listenPopState();
        this.listenLink();
    }
    //監聽popstate
    listenPopState(){
        window.addEventListener('popstate',(e)=>{
            let state = e.state || {},
                path = state.path || '';
            this.dealPathHandler(path)
        },false)
    }
    //全局監聽click事件
    //判斷e.target.tagName是否爲a標籤以及有無href屬性,有則阻止
    listenLink(){
        window.addEventListener('click',(e)=>{
            let dom = e.target;
            if(dom.tagName.toUpperCase() === 'A' && dom.getAttribute('href')){
                e.preventDefault()
                this.assign(dom.getAttribute('href'));
            }
        },false)
    }
    //用於首次進入頁面時調用
    load(){
        let path = location.pathname;
        this.dealPathHandler(path)
    }
    //用於註冊每一個視圖
    register(path,callback = function(){}){
        this.routers[path] = callback;
    }
    //用於註冊首頁
    registerIndex(callback = function(){}){
        this.routers['/'] = callback;
    }
    //用於處理視圖未找到的狀況
    registerNotFound(callback = function(){}){
        this.routers['404'] = callback;
    }
    //用於處理異常狀況
    registerError(callback = function(){}){
        this.routers['error'] = callback;
    }
    //跳轉到path
    assign(path){
        history.pushState({path},null,path);
        this.dealPathHandler(path)
    }
    //替換爲path
    replace(path){
        history.replaceState({path},null,path);
        this.dealPathHandler(path)
    }
    //通用處理 path 調用回調函數
    dealPathHandler(path){
        let handler;
        //沒有對應path
        if(!this.routers.hasOwnProperty(path)){
            handler = this.routers['404'] || function(){};
        }
        //有對應path
        else{
            handler = this.routers[path];
        }
        try{
            handler.call(this)
        }catch(e){
            console.error(e);
            (this.routers['error'] || function(){}).call(this,e);
        }
    }
}
複製代碼

history與hash的選擇

hash相比於history的優勢dom

  1. 兼容性更好
  2. 不會出現直接訪問url會提示404的狀況

hash相比於history的缺點

  1. 錨點功能失效
  2. 不能將相同的hash值加入到歷史棧中,history的pushState方法能夠。
相關文章
相關標籤/搜索