|

前端页面路由管理:history 与 location

现在H5的页面应用越来越多,也有更多的在前端页面做路由管理的需求,尤其是 VueReact 之类的前端框架出现以后,使得 SPA 模式成为可能,在该模式下将大量使用到路由管理。

本篇主要从 history 和 location 两方面来介绍前端页面的跳转以及路由,最后将着重介绍 history.pushStatehistory.replaceState 两个方法,以及对 popstate 时间的监听。

location 对象

window.location 是一个只读属性,返回一个有关文档的当前位置信息的 Location 对象。虽然 location 对象是只读的,但是依然可以给 location.href 指定一个URL字符串,页面将主动跳转到该字符串指定的地址.

使用 location.assgin() 方法与指定 location.href 的值是等价的:

let targetUrl = "https://www.baidu.com";

localtion.href = targetUrl;
// 等价于
location.assign(targetUrl);

可以通过使用 # 来为前端页面增加锚点,实现类似路由的功能,例如:

<button onclick="userClick()">跳转到APP</button>

触发:

let target = "#app";
let localurl = location.href;

function userClick (e) {
    location.href = localurl + target;
}

用户点击按钮后,页面将跳转到 #app 的位置,同时 #app 也将保存在 history 历史中。打印 history.length ,将得到 2 。

我们可以在 #app 的后面加上查询信息,就跟普通的URL一样,这样也可以做到针对特定目标的路由:

<button onclick="userClick(event, 1)">跳转到APP1</button>
<button onclick="userClick(event, 2)">跳转到APP2</button>

触发:

let target = "#app";
let localurl = location.href;

function userClick (e, id) {
    location.href = localurl + target + '?id=' + id;
}

这种基于锚点的方式在路由地址改变时不会发起请求,只要后面的 id 与当前页面的地址不同,history 就会自动保存历史。

history 对象

history 的常用方法有 go()backforward,这三个方法只要用来在历史记录中前进、后退或跳到某条记录。

单后,HTML5 规范出来以后,history 对象又增加了两个方法:

  • pushState,向当前历史中增加一条记录;
  • replaceState,修改当前记录的值,但不会增加新的记录。

上述两个方法是 HTML5 新增的,使用时需要做功能检测:

if (!!(window.history && history.pushState)) {
    // 支持时执行
} else {
    // 不支持时执行
}

pushSate() 方法

history.pushState() 方法接受三个参数,依次为:

  • state:一个与指定网址相关的状态对象,popstate 事件触发时,该对象会传入回调函数,如果不需要这个对象,此处可以填null;

  • title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填 null;

  • url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。

看一个例子,还是相同的按钮,但是改一下他的事件函数:

function userClick (e, id) {
    var stateObj = { targer: 'app' };
    history.pushState(stateObj, null, 'id/' + id);
}

再次单击按钮,地址栏的URL就会变成 /id/1,这个看起来要比 ?id=1 看起来舒服多了,同时,history 的历史记录了也多了一条记录。

需要注意,调用 pushState() 方法后 ,浏览器会立刻在地址栏显示新地址,但是浏览器并不会向服务器发起请求,这个地址也只是成功当前页面历史记录中的一条。同时,即便参数 URL 包含了一个锚点值(即hash),也并不会触发 hashchange 事件,如果设置了一个跨域网址,则会报错。

replaceSate() 方法

history.replaceState() 方法的参数与 pushState 方法一模一样,区别是它修改浏览历史中当前纪录。

看一个经典的例子:

// 假设页面是新开页面,页面不存在历史
console.log(history.length);    // 1
history.pushState({page: 1}, null, '?page=1');
console.log(history.length);    // 2
history.replaceState({page: 2}, null, '?page=2');
history.replaceState({page: 3}, null, '?page=3');
history.replaceState({page: 4}, null, '?page=4');
history.replaceState({page: 5}, null, '?page=5');
console.log(history.length);    // 2

来解析分析一下。

一个新打开的页面,在没有其他历史记录的情况下,history.length 为 1 ,我们使用 pushState() 方法推入一个新 URL ,产生了一条记录,此时输出 history.length 的值为 2,后续我们使用四次 replaceState() 方法替换当前 URL ,虽然地址栏的地址在变,但是并没有产生新的记录,所以最后输出的 history,length 的值依然为 2 。

popstate 事件

说到 history.pushStatehistory.replaceState 就不得不说 popstate 事件。每当同一个文档的浏览历史(即history对象)出现变化时,就会触发 popstate 事件。这个事件绑定在 window 对象上,可以通过 onpopstate 属性来定义事件回调函数。使用的时候,可以为 popstate 事件指定回调函数。这个回调函数的参数是一个 event 事件对象,它的state属性指向 pushState 和 replaceState 方法为当前URL所提供的状态对象(即这两个方法的第一个参数)。

window.onpopstate = function (event) {
    console.log(event.state);
}

可以使用 addEventListener 添加事件绑定:

window.addEventListener('popstate', function (event) {
    console.log(event.state);
});

当然也可以通过 history 对象直接获取当前的 state 值:

var currentState = history.state;

需要注意的是,仅仅调用 pushState 方法或 replaceState 方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用 back、forward、go 方法时才会触发。另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。

引申:刷新当前页面

基于 location 和 history 的特性,通过 JavaScript 刷新当前页面可以有两个快捷操作。

使用 location 的 href 属性刷新当前页面:

location.href = location.href;
// 或者
location.href += '';

使用 history 的 go() 方法刷新当前页面:

history.go(0);

上面两个方法都是针对当前页面的当前 URL 进行刷新。

类似文章

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注