如何在不跳过文档的情况下更新window.location.hash?

ale*_*lex 155 javascript hash jquery scrollto

我的网站上有一个滑动面板.

完成动画后,我就像这样设置哈希

function() {
   window.location.hash = id;
}
Run Code Online (Sandbox Code Playgroud)

(这是一个回调,并且id之前已分配).

这很好用,允许用户为面板添加书签,也可以使非JavaScript版本工作.

但是,当我更新哈希时,浏览器会跳转到该位置.我想这是预期的行为.

我的问题是:我该如何防止这种情况?即如何更改窗口的哈希值,但如果哈希存在则浏览器不会滚动到该元素?某种event.preventDefault()事情?

我正在使用jQuery 1.4和scrollTo插件.

非常感谢!

更新

这是更改面板的代码.

$('#something a').click(function(event) {
    event.preventDefault();
    var link = $(this);
    var id = link[0].hash;

    $('#slider').scrollTo(id, 800, {
        onAfter: function() {

            link.parents('li').siblings().removeClass('active');
            link.parent().addClass('active');
            window.location.hash = id;

            }
    });
});
Run Code Online (Sandbox Code Playgroud)

Att*_*lop 241

通过在现代浏览器上使用历史记录API以及旧版本的回退,可以解决此问题:

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}
Run Code Online (Sandbox Code Playgroud)

幸得利·贝罗

  • @DavidCook - 我们也可以使用`history.replaceState`(对于哈希更改,可能更有意义),以避免需要`popstate`事件监听器. (28认同)
  • 请注意,pushState具有向浏览器历史堆栈添加状态的侧(缩进)效果.换句话说,当用户单击后退按钮时,除非您还添加了一个popstate事件侦听器,否则不会发生任何事情. (10认同)

Der*_*ker 52

问题是您将window.location.hash设置为元素的ID属性.无论您是否"preventDefault()",它都是浏览器跳转到该元素的预期行为.

解决这个问题的一种方法是使用任意值为哈希添加前缀,如下所示:

window.location.hash = 'panel-' + id.replace('#', '');
Run Code Online (Sandbox Code Playgroud)

然后,您需要做的就是检查页面加载时的前缀哈希值.作为额外的奖励,您甚至可以平滑滚动到它,因为您现在可以控制哈希值...

$(function(){
    var h = window.location.hash.replace('panel-', '');
    if (h) {
        $('#slider').scrollTo(h, 800);
    }
});
Run Code Online (Sandbox Code Playgroud)

如果您需要它始终工作(而不仅仅是初始页面加载),您可以使用函数来监视哈希值的更改并即时跳转到正确的元素:

var foundHash;
setInterval(function() {
    var h = window.location.hash.replace('panel-', '');
    if (h && h !== foundHash) {
        $('#slider').scrollTo(h, 800);
        foundHash = h;
    }
}, 100);
Run Code Online (Sandbox Code Playgroud)

  • 很好的解决方案,但削弱了 OP 解决方案,因为它否定了书签部分的使用 (3认同)
  • 这是实际回答问题的唯一解决方案 - 允许散列而不跳跃 (2认同)

Gav*_*ock 27

廉价和讨厌的解决方案..使用丑陋的#!样式.

设置它:

window.location.hash = '#!' + id;
Run Code Online (Sandbox Code Playgroud)

阅读它:

id = window.location.hash.replace(/^#!/, '');
Run Code Online (Sandbox Code Playgroud)

由于它与页面中的匹配和锚点或id不匹配,因此不会跳转.

  • +1我认为你的是最有效的:) (2认同)
  • 我必须保持与IE 7和网站的一些移动版本的兼容性.这个解决方案对我来说是最干净的.一般来说,我会遍布pushState解决方案. (2认同)
  • 设置哈希值:``window.location.hash = '#/' + id;```,然后将其替换为:``window.location.hash.replace(/^#\//, '# ');``` 会美化一下 url -> ```projects/#/tab1``` (2认同)

小智 13

为什么不获取当前滚动位置,将其放入变量然后分配哈希并将页面滚动回原位:

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;
Run Code Online (Sandbox Code Playgroud)

这应该工作

  • 嗯,这对我有用了一段时间,但在过去几个月的某个时候,它在 Firefox 上停止了工作...... (2认同)

ald*_*ans 10

我使用现代浏览器的Attila Fulop(Lea Verou)解决方案和旧浏览器的Gavin Brock解决方案的组合如下:

if (history.pushState) {
    // IE10, Firefox, Chrome, etc.
    window.history.pushState(null, null, '#' + id);
} else {
    // IE9, IE8, etc
    window.location.hash = '#!' + id;
}
Run Code Online (Sandbox Code Playgroud)

正如Gavin Brock所观察到的,为了捕获id,你必须处理字符串(在这种情况下可以有或没有"!"),如下所示:

id = window.location.hash.replace(/^#!?/, '');
Run Code Online (Sandbox Code Playgroud)

在此之前,我尝试了类似于user706270提出的解决方案,但它与Internet Explorer不兼容:因为它的Javascript引擎不是很快,你可以注意到滚动增加和减少,这会产生令人讨厌的视觉效果.