如何替换位置哈希并仅保留最后一个历史记录条目?

18

我正在使用 jQuery BBQ 插件 来跟踪用户在页面中的进度。但是,我只想在用户的历史记录中创建一个额外的条目,而不是每次哈希变化都创建一个。

我已经尝试使用 jQuery.bbq.pushStatemerge_mode 方法,但没有成功:新的历史记录条目仍然被添加:

jQuery.bbq.pushState({ sort: encodeURIComponent(sort) });

我也尝试过location.replace(),但这对Safari 5.1.2不起作用。

location.replace('#' + encodeURIComponent(sort))

如何跨浏览器修改哈希值,同时不会在历史记录中添加太多条目?


1
你是否已经使用过replaceState而不是pushState - Rob W
我在库http://benalman.com/code/projects/jquery-bbq/docs/files/jquery-ba-bbq-js.html中没有看到这样的方法。@Rob W - Hoppe
1
我实际上是指history.replaceState方法。*另请参阅History.js*。 - Rob W
history.replaceState在IE 9以下的浏览器中无法工作,所以我接下来会尝试使用history.js @RobW - Hoppe
@RobW,看起来HTML4浏览器不允许此功能工作,并且只在历史记录中创建1个条目。感谢您的帮助! - Hoppe
2个回答

39

首先,我展示函数replaceHash的定义,该函数仅接受一个参数:新的位置哈希值。逻辑的详细解释可以在答案底部找到。

代码:

// Should be executed BEFORE any hash change has occurred.
(function(namespace) { // Closure to protect local variable "var hash"
    if ('replaceState' in history) { // Yay, supported!
        namespace.replaceHash = function(newhash) {
            if ((''+newhash).charAt(0) !== '#') newhash = '#' + newhash;
            history.replaceState('', '', newhash);
        }
    } else {
        var hash = location.hash;
        namespace.replaceHash = function(newhash) {
            if (location.hash !== hash) history.back();
            location.hash = newhash;
        };
    }
})(window);
// This function can be namespaced. In this example, we define it on window:
window.replaceHash('Newhashvariable');

函数逻辑

  • 如果支持history.replaceState方法,则该函数将始终替换当前哈希,没有任何副作用。
  • 否则,创建指向第一个location.hash属性的引用(hash),并定义以下函数:

    1. 如果location.hash != hash,则我们确定历史状态至少超过了第一次页面视图。 安全地返回历史记录而不卸载页面。 history.back(); // 返回历史记录
    2. 然后设置location.hash属性。 如果在上一步中返回到历史记录,则覆盖历史记录条目。


    后备(最后)方法可能并不总是替换历史记录:
    location.hash == hash时,可能存在以下情况:

    1. 哈希尚未更改,因此返回到上一页毫无意义。
    2. 用户可能已向后导航到原始页面的状态。 如果使用history.back();,则可能会卸载页面,这是不可取的。


    因此,为了安全起见,当哈希等于保存的原始哈希时,永远不要卸载页面。

    注意:在哈希更改之前运行此代码非常重要。 当哈希已经更改时,脚本就不再可靠了。用户可能已导航到第一个哈希状态,它不等于保存的hash。 因此,history.back()会卸载页面。


这正是我一直在寻找的 - 非常感谢您发布这段代码! - verism

23
你可以使用window.locationreplace方法,不需要第二个newSubStr参数。这在所有已知的浏览器中都有效,甚至适用于老旧的IE浏览器:
function replaceHash(hash) {
  return window.location.replace(
    '#' + hash.replace(/^#/, '')
  );
}
请注意,如果文档中有有效元素(按规范所述),页面将跳转/滚动到该元素。

不太对,location.replace 实际上是重新加载页面。 - makc
1
@makc,你能提供更多细节吗?使用的是哪个浏览器,哪个版本? - yckart
我刚刚尝试了location.replace(location.href.spli('#')[0])来去掉这里的哈希标记。在chrome@mac中,这将重新加载页面。 - makc
如果你只是传递哈希值,它仍然会保存在历史记录中 :( - makc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接