资讯专栏INFORMATION COLUMN

前端路由实现-history

YacaToy / 2162人阅读

摘要:首发前端路由实现了解新增了两个和两个都接收三个参数状态对象一个对象,与用方法创建的新历史记录条目关联。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。该参数是可选的不指定的话则为文档当前。

首发:前端路由实现(history)

了解

HTML5 history新增了两个API:history.pushStatehistory.replaceState

两个API都接收三个参数:

状态对象(state object):一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。

标题(title):FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。

地址(URL): 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

相同之处是两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新。

不同之处在于pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。

这里大家可以先F12试试,看看地址栏发生了什么变化

window.history.pushState(null, null, "hell");

window.history.pushState(null, null, "/hell");

window.history.pushState(null, null, "#/hello");

window.history.pushState(null, null, "?name=");
注意:这里的url不支持跨域,否则会抛出异常
尝试

index.html




    
    
    
    前端路由实现
    
    


    
一:简单开胃菜

router.js

;(function(){      
      history.replaceState(null,null,"");//最开始的状态,采用replace直接替换
    $("#router").html("

nav1

") $("a").on("click",function(){ console.log(this.text) var text = this.text; $("#router").html("

"+ text +"

") history.pushState(null,null,"#/"+text); }) })()

最简单的示例,只能监听点击事件,而浏览器中的后、前进都不能监听地址栏的改变

二、数据状态管理

router.js

状态版
;(function(){      
      var count = [0,0,0]
      $("#router").html("

导航1:

"+count[0]+"

导航2:

"+count[1]+"

导航3:

"+count[2]) history.replaceState(count,null,"");//最开始的状态,采用replace直接替换 for(var i = 0 ; i<$("a").length; i++){ $("a")[i].index = i $("a").eq(i).on("click",function(){ console.log(this.index); var index = this.index; count[index]++; $("#router").html("

导航1:

"+count[0]+"

导航2:

"+count[1]+"

导航3:

"+count[2]) history.pushState(count,null,"#/count"+count[index]);//之后的状态,需要进行保存 }) } //监听history其他api导致地址栏url改变事件 window.addEventListener("popstate",function(e){ console.log(e.state); var state = e.state; $("#router").html("

导航1:

"+state[0]+"

导航2:

"+state[1]+"

导航3:

"+state[2]) }) })()

popstate

当活动历史记录条目更改时,将触发popstate事件。如果被激活的历史记录条目是通过对history.pushState()的调用创建的,或者受到对history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。

需要注意的是调用history.pushState()或history.replaceState()不会触发popstate事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back())

三:回归简单

router.js

;(function(){      
      
      var url = "nav1";

      history.replaceState(url,null,"");//最开始的状态,采用replace直接替换
    $("#router").html("

"+url+"

") $("a").on("click",function(){ console.log(this.text) url = this.text; $("#router").html("

"+ url +"

") history.pushState(url,null,"#/"+url); }) window.addEventListener("popstate",function(e){ console.log(e.state); url = e.state $("#router").html("

"+ url +"

") }); })()

兜兜转转我们算是回到了起点,但是通过这张图我们会发现页面点击刷新按钮会有导航和内容块不一致的内容,所以我们需要改进他,并且监听load事件

改进

;(function(){      
      
    $("a").on("click",function(){
        console.log(this.text)
        url = this.text;

        $("#router").html("

"+ url +"

") history.pushState(url,null,"#/"+url); }) window.addEventListener("popstate",function(e){ console.log(e.state); url = e.state $("#router").html("

"+ url +"

") }); window.addEventListener("load",function(){ url = location.hash.slice(2) || "nav1"; history.replaceState(url,null,""); console.log(location.hash); $("#router").html("

"+ url +"

"); }); })()

可以看到我们点击刷新的时候导航和内容区域一致了。

四:路由页面引进

我们这里还是采用了ajaxload方法

router.js

;(function(){ 


    var router = [
          {
              "path":"index",
              "url":"./main.html"
          },
          {
              "path":"news",
              "url":"./news.html"
          },
          {
              "path":"about",
              "url":"./about.html"
          }
      ];

      //改变页面
      function display_page(url){
          $("#router").load(url)
      }

    $("a").on("click",function(){
        var path = $(this).data("path");
        console.log(path)
        for(var i in router){
            if(router[i].path == path){
                display_page(router[i].url);
                history.pushState(router[i].url,null,router[i].path);
            }
        }
    })
    window.addEventListener("popstate",function(e){
        var url = e.state;
        display_page(url);
        
    });
    window.addEventListener("load",function(){
        var start = location.href.lastIndexOf("/");

        var path = location.hash.slice(start) || "index";
        console.log(path)

        for(var i in router){//刷新 加载
            console.log(1)
            if(router[i].path == path){
                display_page(router[i].url);    
                history.replaceState(router[i].url,null,path);        
                break;    
            }
            if(i == router.length-1){//重定向
                display_page(router[0].url);    
                history.replaceState(router[i].url,null,router[0].path);    
            }
        }                        
    });

})()


可以看到基本是实现了history路由功能,但是这里有一个问题就是刷新后因为地址栏url原因会报错,也就是找不到这个页面,这是由于刷新的时候是重载,重新向网站目录查找文件,而我们当前目录并没有这个文件资源所以导致报错。需要后台拦截! 放弃!

折中

最后我还是屈服于#

;(function(){      
      
      var router = [
          {
              "path":"index",
              "url":"./main.html"
          },
          {
              "path":"news",
              "url":"./news.html"
          },
          {
              "path":"about",
              "url":"./about.html"
          }
      ];

      //改变页面
      function display_page(url){
          $("#router").load(url)
      }

    $("a").on("click",function(){
        var path = $(this).data("path");
        console.log(path)
        for(var i in router){
            if(router[i].path == path){
                display_page(router[i].url);
                history.pushState(router[i].url,null,"#/"+router[i].path);
            }
        }
    })
    window.addEventListener("popstate",function(e){
        var url = e.state;
        display_page(url);
        
    });
    window.addEventListener("load",function(){
        var path = location.hash.slice(2) || "/index";
        console.log(path)
        for(var i in router){//刷新 加载
            console.log(1)
            if(router[i].path == path){
                display_page(router[i].url);    
                history.replaceState(router[i].url,null,"#/" + path);        
                break;    
            }
            if(i == router.length-1){//重定向
                display_page(router[0].url);    
                history.replaceState(router[0].url,null,"#/" + router[0].path);    
            }
        }                        
    });

})();

勉强的很呀

代码: router(history)
演示: 演示地址

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

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

相关文章

  • [实践系列]-前端路由

    摘要:而应用便是基于前端路由实现的所以便有了前端路由。因为两种模式都需要调用一个方法来实现不同路由内容的刷新前端路由路由列表匹配当前的路由匹配不到则使用配置内容并渲染下面我们来实现两种模式。 什么是路由? 路由这概念最开始是在后端出现的,在以前前后端不分离的时候,由后端来控制路由,服务器接收客户端的请求,解析对应的url路径,并返回对应的页面/资源。 简单的说 路由就是根据不同的url地...

    guyan0319 评论0 收藏0
  • 前端路由原理解析和实现

    摘要:如何实现前端路由要实现前端路由,需要解决两个核心如何改变却不引起页面刷新如何检测变化了下面分别使用和两种实现方式回答上面的两个核心问题。 原文链接:github.com/whinc/blog/… 在单页应用如此流行的今天,曾经令人惊叹的前端路由已经成为各大框架的基础标配,每个框架都提供了强大的路由功能,导致路由实现变的复杂。想要搞懂路由内部实现还是有些困难的,但是如果只想了解路由实现基本...

    lavor 评论0 收藏0
  • 前端路由实现与 react-router 源码分析

    摘要:回调函数将在更新时触发,回调中的起到了新的的作用。注册回调在中使用注册的回调函数,最终放在模块的回调函数数组中。 原文地址:https://github.com/joeyguo/blog/issues/2 在单页应用上,前端路由并不陌生。很多前端框架也会有独立开发或推荐配套使用的路由系统。那么,当我们在谈前端路由的时候,还可以谈些什么?本文将简要分析并实现一个的前端路由,并对 reac...

    ISherry 评论0 收藏0
  • 自己动手实现一个前端路由

    摘要:单页面应用利用了动态变换网页内容避免了页面重载路由则提供了浏览器地址变化网页内容也跟随变化两者结合起来则为我们提供了体验良好的单页面应用前端路由实现方式路由需要实现三个功能浏览器地址变化切换页面点击浏览器后退前进按钮,网页内容跟随变化刷新浏 单页面应用利用了JavaScript动态变换网页内容,避免了页面重载;路由则提供了浏览器地址变化,网页内容也跟随变化,两者结合起来则为我们提供了体...

    psychola 评论0 收藏0
  • Web开发中路由实现原理

    摘要:开发中路由实现原理开发中路由实现原理服务端路由路由前端路由实现比较参考什么是路由根据不同的地址,展示不同的页面或者更新页面局部视图服务端路由服务器端路由管理,常见的开发模式是前端根据的不同,使用发起异步请求,获取不同的页面资源,前端获取资源 Web开发中路由实现原理 Web开发中路由实现原理 服务端路由 Hash路由 History 前端路由实现比较 参考: 什么是路由: 根据不同...

    Elle 评论0 收藏0

发表评论

0条评论

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