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


163

我在网站上设置了一个滑动面板。

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

function() {
   window.location.hash = id;
}

(这是一个回调,并且在之前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;

            }
    });
});

2
我认为您已经尝试了event.preventDefault():)
Marko 2010年

@Marko我不知道在哪里放置它!
Alex

您可以发布其余代码吗?
Marko 2010年

@Marko Ivanovski我认为这无关紧要,但是我会看看我能做什么。
Alex

3
@Gareth我认为没有合适的地方,因为它在我更新哈希后立即发生。
Alex

Answers:


261

有一种解决方法,可以在现代浏览器上使用历史记录API,而在旧浏览器上进行回退:

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

幸得利·贝罗


我认为这是更好的答案。
格雷格·安南代尔

10
请注意,pushState具有将状态添加到浏览器历史记录堆栈的副作用(缩进)。换句话说,当用户单击“后退”按钮时,除非您还添加popstate事件侦听器,否则不会发生任何事情。
大卫·库克

32
@DavidCook-我们也可以使用history.replaceState(对于散列更改,可能更有意义),以避免需要popstate事件侦听器。
2014年

这对我有用。我喜欢历史变化的影响。我想补充一点,这不会触发hashchange事件。那是我必须解决的问题。
约旦

警告!这不会触发hashchange事件
圣地亚哥·亚利桑那

52

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

解决此问题的一种方法是为哈希值加上一个任意值,如下所示:

window.location.hash = 'panel-' + id.replace('#', '');

然后,您要做的就是检查页面加载时是否带有前缀的哈希。另外,由于您现在可以控制哈希值,因此甚至可以平滑滚动到它。

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

如果您需要始终保持这种状态(而不仅仅是在初始页面加载时),则可以使用一个函数来监视对哈希值的更改,并即时跳转到正确的元素:

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

2
这是唯一能真正回答问题的解决方案-允许散列而不跳转
amosmos

这确实回答了这个问题,解释了如何为哈希添加和删除任意值,以避免默认浏览器行为导致的跳转。
lowtechsun '16

1
好的解决方案,但是却削弱了OP的解决方案,因为它否定了使用书签部分的做法
Samus

27

便宜又讨厌的解决方案..使用丑陋的#!样式。

要设置它:

window.location.hash = '#!' + id;

阅读:

id = window.location.hash.replace(/^#!/, '');

由于它与页面不匹配并锚定或标识,因此它不会跳转。


3
我必须保留与IE 7和该网站的某些移动版本的兼容性。这个解决方案对我来说是最干净的。通常,我会遍历pushState解决方案。
埃里克·古德温

1
设置哈希::window.location.hash = '#/' + id;,然后替换为:window.location.hash.replace(/^#\//, '#');将美化网址-> projects/#/tab1
braitsch 2015年

13

为什么不获取当前滚动位置,将其放在变量中,然后分配哈希值,然后将页面滚动回到原来的位置:

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;

这应该工作


1
嗯,这为我工作了一段时间,但是在过去的几个月中,这已经停止了在Firefox上的工作....
matchew

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;
}

正如Gavin Brock观察到的那样,要捕获ID,您必须按以下方式处理字符串(在这种情况下,该字符串可以有或没有“!”):

id = window.location.hash.replace(/^#!?/, '');

在此之前,我尝试了一种类似于user706270提出的解决方案,但是它不适用于Internet Explorer:由于其Javascript引擎不是很快,您可以注意到滚动的增加和减少,从而产生了讨厌的视觉效果。


2

这个解决方案对我有用。

设置的问题location.hash是,如果在页面上找到该页面,该页面将跳转到该ID。

问题window.history.pushState在于它为用户单击的每个选项卡添加了一个条目到历史记录中。然后,当用户单击back按钮时,他们将转到上一个选项卡。(这可能是或不是您想要的。这不是我想要的)。

对我而言,replaceState更好的选择是仅替换当前历史记录,因此,当用户单击back按钮时,他们将转到上一页。

$('#tab-selector').tabs({
  activate: function(e, ui) {
    window.history.replaceState(null, null, ui.newPanel.selector);
  }
});

在MDN上查看History API文档


1

我不确定是否可以更改原始元素,但是从使用id attr切换到其他类似data-id的方法又如何呢?然后只需读取您的哈希值的data-id值,它就不会跳转。


1

这个解决方案对我有用

// store the currently selected tab in the hash value
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
$('#myTab a[href="' + hash + '"]').tab('show');

我的完整js代码是

$('#myTab a').click(function(e) {
  e.preventDefault();
  $(this).tab('show');
});

// store the currently selected tab in the hash value
$("ul.nav-tabs > li > a").on("shown.bs.tab", function(e) {
  var id = $(e.target).attr("href").substr(1);
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }
   // window.location.hash = '#!' + id;
});

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
// console.log(hash);
$('#myTab a[href="' + hash + '"]').tab('show');

0

当使用laravel框架时,由于使用了route-> back()函数,因此删除了我的哈希,因此出现了一些问题。为了保留我的哈希,我创建了一个简单的函数:

$(function() {   
    if (localStorage.getItem("hash")    ){
     location.hash = localStorage.getItem("hash");
    }
}); 

然后将其设置在我的其他JS函数中,如下所示:

localStorage.setItem("hash", myvalue);

您可以根据自己的喜好命名本地存储值。我的名字hash

因此,如果在PAGE1上设置了哈希,然后您导航到PAGE2;当您在PAGE2上单击“上一步”时,哈希将在PAGE1上重新创建。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.