资讯专栏INFORMATION COLUMN

利用pushState, popState和location.hash等方法自己实现一个小型路由

ysl_unh / 1836人阅读

摘要:最后通过这些自己实现小型的路由。对象还提供方法这个方法用以监听浏览器在不同历史记录中进行切换,而触发相应的事件。这时调用方法后页面回退,同时页面发生刷新这时无法监听这个事件。所以可以进行降级使用来进行路由设计。不过,还提供了一个。

这篇文章主要是记录下HTML5中history提供的pushState, replaceStateAPI。最后通过这些API自己实现小型的路由。

关于window.history提供的API请参见Mozilla文档

其中history提供的pushStatereplaceState2个API提供了操作浏览器历史栈的方法。

其中pushState:

    
    history.pushState(data, null, "#/page=1");
    
    pushState接收3个参数,第一个参数为一个obj,表示浏览器
    
    第二个参数是document.title的值,一般设定为`null`
    
    第三个参数string,用以改变 当前url

pushState方法在改变url的同时向浏览器历史栈中压入新的历史记录。

接收url的参数为string类型,用以改变当前地址栏的url.需要注意的一点就是这个参数不能和跨域,即协议,域名,端口必须都是相同的,如果出现跨域的情况,即会提示:

Uncaught DOMException: Failed to execute "pushState" on "History": A history state object with URL "http://www.baidu.com/" cannot be created in a document with origin "http://commanderXL.com" and URL 

Example:

    
    打开www.baidu.com

    history.pushState(null, null, "?page=1")
    //地址栏变成 www.baidu.com/?page=1
    
    history.pushState(null, null, "#page=2");
    //地址栏变成 www.baidu.com/#page=2

其中replaceState:

    history.replaceState(null, null, "#page=2");

replaceState接收的参数pushState相同,但是最终的效果是:地址栏url会根据接收的参数而变化,但是浏览器并未在当浏览历史栈中增加浏览器的历史记录,而是替换当前的浏览器历史记录。

通过pushStatereplaceState虽然能改变URL,但是不会主动触发浏览器reload

window对象还提供popstate方法:

    window.addEventListener("popstate", function() {
        
    });

这个方法用以监听浏览器在不同历史记录中进行切换,而触发相应的事件。

在浏览器提供的history对象上还有go, back方法,用以模拟用户点击浏览器的前进后退按钮。在某个web应用当中,比如点击了标签,发生了页面的跳转。这时调用history.back();方法后页面回退,同时页面发生刷新,这时window.onpopstate无法监听这个事件。但是如果是通过pushState或者replaceState来改变URL且不发生浏览器刷新的话,再使用history.back()history.go(),这样popstate事件会被触发。

    
    history.pushState({page: 1}, null, "?page=1");
    history.pushState({page: 2}, null, "?page=2");

    history.back(); //浏览器后退

    window.addEventListener("popstate", function(e) {
        //在popstate事件触发后,事件对象event保存了当前浏览器历史记录的状态.
        //e.state保存了pushState添加的state的引用
        console.log(e.state);  //输出 {page: 1}
    });

PS: 通过pushState在url上添加?page=1可以通过location.search去获取search的内容。不过如果通过location.search去改变url的话是会主动触发浏览器reload的。这个特性可以和下面将的关于hash的内容对比下。

API大致了解了,那么这些方法可以运用到哪些地方呢?一个比较常用的场景是就在单页应用中,通过这些API完成前端的路由设计,利用pushState, replaceState可以改变url同时浏览器不刷新,并且通过popstate监听浏览器历史记录的方式,完成一系列的异步动作。

    
    
    
    //路由
    const Router = [];
    
    const addRoute = (path = "", handle = () => {}) => {
        let obj = {
            path,
            handle
        }
        
        Router.push(obj);
    }
    
    
    //添加路由定义
    addRoute("/post", function() {
        //do something
    });
    
    addRoute("/login", function() {
        //do something
    })
    
    
    //路由处理
    const routeHandle = (path) => {
        Router.forEach((item, index) => {
            if(item.path === path) {
                item.handle.apply(null, [path]);
                return true;
            }
        })
        return false;
    }
    
    
    //拦截默认的a标签行为
    document.addEventListener("click", function(e) {
        let dataset = e.target.dataset;
        if(dataset) {
            if(routeHandle(dataset.href)) {
                //阻止默认行为
                e.preventDefault();
            }
        }
    })

大致的实现思路就是,通过添加路由信息,然后拦截标签的默认行为,并与注册的路由信息进行匹配。若匹配成功调用对应的handle方法.

不过pushStatereplaceState方法在低版本的IE浏览器下兼容性不是很好。所以可以进行降级使用hash来进行路由设计。

hash?请戳我。

可以通过location.hash获取url上第一个#(fragment)及后面的内容。同时还能通过location.hash改写其内容,且不会主动触发浏览器reload。 有些功能是不是和pushStatereplaceState一样? 所以为了兼容到低版本的浏览器,可以通过监听#变化来进行路由设计。

那么如何去监听呢? 比较粗暴的一种方式就是polling

    
    var oldHash = location.hash;
    setTimeInterval(function() {
        if(oldHash !== location.hash) {
            
            //do something
        
            oldHash = location.hash;
        }
    }, 100);

不过,H5还提供了一个API: hashchange。它的就可以直接代替上面的polling方法,来监听#的变化。

    window.addEventListener("hashchange", function() {
        routeHandle(locaiton.hash);
    });

这个小型的路由设计可以参见我的github.

稍微总结下:

上面主要介绍了history提供的一些API,hash的相关知识。在平时可以运用到SPA当中,Gmail就是通过hash来进行路由设计的。它相对于页面跳转来说:

页面只需要加载一次。后面的页面切换可以通过ajax去请求数据。页面体验更加流畅;

可以利用本地缓存,优化页面体验。在不同页面切换的过程中更加流畅;

可进行按需加载...

等等一些实用的好处吧。

项目地址

项目地址请戳我

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80680.html

相关文章

  • 从了解HashHtml5 History 到简单实现路由

    摘要:原因在于将状态对象保存在用户的磁盘上,以便在用户重启浏览器时使用,我们规定了状态对象在序列化表示后有的大小限制。新不必须为绝对路径。新必须与当前同源,否则会抛出一个异常。注意绝对不会触发事件,即使新的与旧的仅哈希不同也是如此。 Hash hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分),在页面中的hash有多种功能意义: 锚点 url: htt...

    Prasanta 评论0 收藏0
  • 从history api看主流框架的路由机制

    摘要:前端路由库的作用是改变地址栏,支持浏览器前进后退,并同步路由对应的视图,这里以及其依赖的库说一下路由机制原文地址前提首先简单介绍一下前端路由机制所依赖的事件及对应的事件对于支持新增方法的浏览器,可以通过设置来在浏览器栈中新增一条记录设置时 前端路由库的作用是改变地址栏,支持浏览器前进、后退,并同步路由对应的视图,这里以react-router及其依赖的history库说一下路由机制 原...

    Lyux 评论0 收藏0
  • SPA中前端路由基本原理与实现方式

    摘要:部分比较重要部分比较重要重点是下面的,这里操作我们借助实现的逻辑不难,但是利用总是没有所谓前端路由的那种味,必然也不是主流方法。而现在的前端路由也是基于这个原理实现的。和异曲同工,而且前者可以在该事件之外任何地方随时使用。 SPA 前端路由原理与实现方式 通常 SPA 中前端路由有2中实现方式,本文会简单快速总结这两种方法及其实现: 修改 url 中 Hash 利用 H5 中的 hi...

    alogy 评论0 收藏0
  • SPA中前端路由基本原理与实现方式

    摘要:部分比较重要部分比较重要重点是下面的,这里操作我们借助实现的逻辑不难,但是利用总是没有所谓前端路由的那种味,必然也不是主流方法。而现在的前端路由也是基于这个原理实现的。和异曲同工,而且前者可以在该事件之外任何地方随时使用。 SPA 前端路由原理与实现方式 通常 SPA 中前端路由有2中实现方式,本文会简单快速总结这两种方法及其实现: 修改 url 中 Hash 利用 H5 中的 hi...

    Shimmer 评论0 收藏0
  • 前端路由跳转基本原理

    摘要:目前前端三杰都推介单页面应用开发模式,在路由切换时替换中最小修改的部分,来减少原先因为多页应用的页面跳转带来的巨量性能损耗。 showImg(https://segmentfault.com/img/bVbn1ZN?w=3069&h=2048); 目前前端三杰 Angular、React、Vue 都推介单页面应用 SPA 开发模式,在路由切换时替换 DOM Tree 中最小修改的部分 ...

    SillyMonkey 评论0 收藏0

发表评论

0条评论

ysl_unh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<