使用scrollspy更新地址栏window.location哈希

我有一个带有scrollspy的菜单(使用twitter boostrap)。 我想在用户向下滚动到下一部分时更新window.location.hash

用户向下滚动时,以下代码有效:

 $(window).on('activate.bs.scrollspy', function (e) { location.hash = $("a[href^='#']", e.target).attr("href") || location.hash; }); 

但是,当用户向上滚动时,它不能很好地工作。

这样做的原因是设置新的location.hash会触发浏览器导航到相应的锚点。 这会触发连锁反应,用户将立即在页面顶部结束。

js-fiddle中的演示

现在解决这个问题最简单的方法是什么?

对于更多跨浏览器哈希更新,您可以使用此JS:

 $(window).on('activate.bs.scrollspy', function(e) { var $hash, $node; $hash = $("a[href^='#']", e.target).attr("href").replace(/^#/, ''); $node = $('#' + $hash); if ($node.length) { $node.attr('id', ''); } document.location.hash = $hash; if ($node.length) { return $node.attr('id', $hash); } }); 

它暂时删除搜索到的哈希,而不是通过window.location添加它,然后恢复相关的哈希值。 不幸的是我不知道这个解决方案的确切兼容性范围,但是肯定支持IE9,也可能支持IE上的所有旧版本(我不关心我的项目中的旧浏览器,所以我没有测试这个解决方案)。

可以使用HTML5历史记录更改URL的状态,而不会触发浏览器遵循新状态。 并非所有浏览器都支持此function 。

使用history.replaceState()还有一个额外的好处,当用户使用浏览器的后退按钮时,它不会先向上滚动。

 $(window).on('activate.bs.scrollspy', function (e) { history.replaceState({}, "", $("a[href^='#']", e.target).attr("href")); }); 

看工作js-fiddle 。

我将它用于Bootstrap v4:

 $(window).on('activate.bs.scrollspy', function(e) { history.replaceState({}, "", $('.nav-item .active').attr("href")); });