您当前的位置:首页 > 计算机 > 编程开发 > Html+Div+Css(前端)

前端路由实现原理(history)

时间:12-14来源:作者:点击数:
城东书院 www.cdsy.xyz

了解

HTML5 history 新增了两个 API:history.pushState 和 history.replaceState

两个 api 都接受三个参数
  • 状态对象(state object):一个 JavaScript 对象,与用 pushState() 方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。
  • 标题(title):FireFox 浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。
  • 地址(URL): 新的历史记录条目的地址。浏览器不会在调用 pushState() 方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前 URL 为基准;传入的URL与当前URL应该是同源的,否则,pushState() 会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

相同之处是两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新。不同之处在于 pushState 会增加一条新的历史记录,而 replaceState 则会替换当前的历史记录

大家可以先在控制台试试,看看地址栏发生了什么变化
window.history.pushState(null, null, "test"); window.history.pushState(null, null, "/test"); window.history.pushState(null, null, "#/hello"); window.history.pushState(null, null, "?name=");

实例演示

建立 html 文件,index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>前端路由实现</title>
    <style>
        .warp{
            width:400px;
            height:400px;
            border:1px solid grey;
            margin:0 auto;
        }
        .nav{
            border-bottom:1px solid grey;
        }
        .nav li{
            display:inline-block;
            list-style:none;
        }
        .nav li a{
            display:inline-block;
            text-decoration: none;
            padding:10px 15px;
        }
        .router{
            padding:20px;
        }
        a{
            cursor: pointer;
        }
    </style>
</head>
<body>
<section>
<div>
<ul>
<li><a href="javascript:void(0)" data-path="index">首页</a></li>
<li><a href="javascript:void(0)" data-path="news">新闻</a></li>
<li><a href="javascript:void(0)" data-path="about">关于</a></li>
</ul>
</div>
<div>
<!-- 内容加载区域 -->
</div>
</section>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="./router.js"></script>
</body>
</html>

此时的页面为:

引入 js 文件 router.js

(function(){   
  history.replaceState(null,null,'');//最开始的状态,采用replace直接替换
  $('#router').html('<p>显示内容区域</p>')
  $('a').on('click',function(){
      console.log(this.text)
      var text = this.text;
      $('#router').html('<p>'+ text +'</p>')
      history.pushState(null,null,'#/'+text);
  })    
})()

此时点击导航按钮时

  • 此时当点击不同的导航项的时候,地址栏上的路由进行了对应的改变,展现的内容区域也发生了变化。但是实际上这个并没有实现路由的真正含义。因为内容部分的改变是根据事件的触发而获得当前的内容。
  • 此时如果点击浏览的前进和后退按钮,内容是无法监听到地址栏的变化而作出改变的
在此基础上变动一下实现方式,将 router.js 改为:
// 状态版
(function(){   
   var count = [0,0,0]
   $('#router').html('<p>首页</p>'+count[0]+'<p>新闻</p>'+count[1]+'<p>关于</p>'+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('<p>首页</p>'+count[0]+'<p>新闻</p>'+count[1]+'<p>关于</p>'+count[2])
console.log(count)
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('<p>首页</p>'+state[0]+'<p>新闻</p>'+state[1]+'<p>关于</p>'+state[2])
})
})()

此时的思路是做一个状态记录,记录下每个导航按钮被点击的次数。当每次执行点击导航栏切换的时候,通过 history.pushState(count, null, '#/count'+count[index]) 这个 api,传递了状态对象在内,并在第三个参数中将当前已点击数作为地址栏的显示数据。

  • 当活动历史记录条目更改时,将触发 popstate 事件。如果被激活的历史记录条目是通过对 history.pushState() 的调用创建的,或者受到对 history.replaceState() 的调用的影响,popstate 事件的 state 属性包含历史条目的状态对象的副本。
  • 需要注意的是调用 history.pushState() 或 history.replaceState() 不会触发 popstate 事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在 Javascript 代码中调用 history.back())
此处通过记录下每次的点击次数来解释了 pushState 的用法以及参数,其实简单的写法可以表达为:
(function(){
var url = '内容展示';
history.replaceState(url,null,'');//最开始的状态,采用replace直接替换
$('#router').html('&lt;p&gt;'+url+'&lt;/p&gt;')
$('a').on('click',function(){
    console.log(this.text)
    url = this.text;
    $('#router').html('&lt;p&gt;'+ url +'&lt;/p&gt;')
    history.pushState(url,null,'#/'+url);
})
window.addEventListener('popstate',function(e){
    console.log(e.state);
    url = e.state
    $('#router').html('&lt;p&gt;'+ url +'&lt;/p&gt;')
 });     
})()

现在的效果看上去其实我们相当于回到了远点,但是解决了无法监听地址栏的地址变化问题,是通过监听 popstate 来作出响应的。现在还只是看了这一部分的路由实现机制,要通过监听作出不同的响应。还需要更深入的与 hash 进行对比。

城东书院 www.cdsy.xyz
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐