前端路由探究--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方法能够。
相关文章
相关标签/搜索