前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >单页面应用history路由实现原理

单页面应用history路由实现原理

作者头像
OECOM
发布2020-07-01 16:57:01
3.1K0
发布2020-07-01 16:57:01
举报
文章被收录于专栏:OECOMOECOM

在单页面应用中history路由是很受欢迎的,它的路由显示方式和传统的路由方式相同,在显示上很美观,比hash的方式看着舒服的多。我们经常使用的api比如push或pushState,replace或replaceState,go,forward,back等等,其实都是和html5内置的history对象息息相关的,其原理就是调用了HTML5的history内置对象,然后进行了一些封装操作。

history对象属性

window 对象通过 history 对象提供了对浏览器的回话历史的访问(不要与 WebExtensions history搞混了,我们要说的这个history变化时是不会请求服务器的)。它暴露了很多有用的方法和属性,允许你在用户浏览历史中向前和向后跳转,同时——从HTML5开始——提供了对history栈中内容的操作。

history对象提供的API 可以实现无刷新更改地址栏链接,配合 AJAX 可以做到无刷新跳转,所以通过history进行路由变化是不会向服务器进行请求的

向前向后跳转

这两个api很简单,只是一条语句就好

代码语言:javascript
复制
history.back()//向后跳转
history.forward()//向前跳转

跳转到指定的点

此api调用方式为:

代码语言:javascript
复制
history.go(1)

go的参数为你要跳转到的url相对当前url的位置标志。向后跳转是负数,向前是正数。

这个api我个人觉得用处不是很大,因为我们操作url要么就是直接向后跳转,要么直接向前跳转,要么就是直接赋值url直接跳转过去。该api需要传入相对的位置标志就会显得略有些麻烦。

跳转到指定的页面

HTML5引入了 history.pushState() 和 history.replaceState() 方法,这两个方法都可以跳转到指定的url页面,主要区别在于replaceState() 是修改了当前的历史记录项而不是新建一个,也就是说history.pushState()之后,history.length会加一,但是replaceState()却不会。 注意这并不会阻止其在全局浏览器历史记录中创建一个新的历史记录项。

我们先来说history.pushState(),其调用方式如下:

代码语言:javascript
复制
history.pushState(state, title, url)

pushState() 需要三个参数: 一个状态对象, 一个标题 (目前被忽略), 和 (可选的) 一个URL. 让我们来解释下这三个参数详细内容:

  • 状态对象: 状态对象state是一个JavaScript对象,通过pushState () 创建新的历史记录条目。无论什么时候用户导航到新的状态,popstate事件就会被触发,能触发popstate事件的是history.back()或history.forword()以及history.go(),pushState()是不会触发的,后面会介绍如何监听pushState事件。该事件的state属性包含该历史记录条目状态对象的副本。
  • 标题:Firefox目前忽略这个参数,但未来可能会用到。传递一个空字符串在这里是安全的,而在将来这是不安全的。二选一的话,你可以为跳转的state传递一个短标题。
  • URL:该参数定义了新的历史URL记录。注意,调用 pushState() 后浏览器并不会立即加载这个URL,但可能会在稍后某些情况下加载这个URL,比如在用户重新打开浏览器时。新URL不必须为绝对路径。如果新URL是相对路径,那么它将被作为相对于当前URL处理。新URL必须与当前URL同源,否则 pushState() 会抛出一个异常。该参数是可选的,缺省为当前URL。

使用示例

代码语言:javascript
复制
history.pushState({msg:"跳转url"}, null, '/oecom');

调用完成以后,如果之前的url为https://www.oecom.cn/history , 那么调用完成以后就会变为:https://www.oecom.cn/oecom

然后我们再来说一下history.replaceState(),他的参数和pushState的参数相同,区别上面我们也说过了,下面我们来看一下具体是什么样子。

代码语言:javascript
复制
history.pushState({msg:"跳转url"}, null, '/oecom1');
history.pushState({msg:"跳转url"}, null, '/oecom2');
history.replaceState({msg:"跳转url"}, null, '/oecom3');

我们调用三次url跳转,前两次使用pushState,后一次使用replaceState,当我们在调用history.back()时,会直接跳转到oecom1路由上,原因就在于replaceState是直接将当前路由替换掉,而不是增加一个。

popstate事件

每当活动的历史记录项发生变化时, popstate 事件都会被传递给window对象。如果当前活动的历史记录项是被 pushState 创建的,或者是由 replaceState 改变的,那么 popstate 事件的状态属性 state 会包含一个当前历史记录状态对象的拷贝

代码语言:javascript
复制
window.onpopstate = function(event) {
  alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
//绑定事件处理函数. 
history.pushState({page: 1}, "title 1", "?page=1");    //添加并激活一个历史记录条目 https://www.oecom.cn/example.html?page=1,条目索引为1
history.pushState({page: 2}, "title 2", "?page=2");    //添加并激活一个历史记录条目 https://www.oecom.cn/example.html?page=2,条目索引为2
history.replaceState({page: 3}, "title 3", "?page=3"); //修改当前激活的历史记录条目 https://www.oecom.cn/example.html?page=2 变为 https://www.oecom.cn/example.html?page=3,条目索引为3
history.back(); // 弹出 "location: https://www.oecom.cn/example.html?page=1, state: {"page":1}"
history.back(); // 弹出 "location: https://www.oecom.cn/example.html, state: null
history.go(2);  // 弹出 "location: https://www.oecom.cn/example.html?page=3, state: {"page":3}

history当前状态

页面加载时,或许会有个非null的状态对象。这是有可能发生的,举个例子,假如页面(通过pushState() 或 replaceState() 方法)设置了状态对象而后用户重启了浏览器。那么当页面重新加载时,页面会接收一个onload事件,但没有 popstate 事件。然而,假如你读取了history.state属性,你将会得到如同popstate 被触发时能得到的状态对象。

你可以读取当前历史记录项的状态对象state,而不必等待popstate 事件, 只需要这样使用history.state 属性:

代码语言:javascript
复制
let currentState = history.state;

上面我们说了popstate事件,这个事件无法监听pushState和replaceState事件,有一个很笨的方式就是采用setInterval轮询的方式来判断history.state是否变化来判断url是否变化,当然这个方法是很消耗性能的。

我们可以采用改写一下pushState方法来实现,思路是在history添加一个onpushState属性,在pushState时进行调用即可。

代码语言:javascript
复制
(function(history){
    var pushState = history.pushState;
    history.pushState = function(state) {
        if (typeof history.onpushstate == "function") {
            history.onpushstate({state: state});
        }
        return pushState.apply(history, arguments);
    };
})(window.history);
//设置其方法和popstate相同即可
window.onpopstate =history.onpushstate= function(event) {
      alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
};

如果要监听replaceState,方法和此方法相同,在此不再赘述。

浏览器支持

Chrome

Safari

Firefox

Opera

IE

Android

iOS

31+

7.1+

34+

11.50+

10+

4.3+

7.1+

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • history对象属性
    • 向前向后跳转
      • 跳转到指定的点
        • 跳转到指定的页面
          • popstate事件
            • history当前状态
            • 浏览器支持
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档