手动滚动到锚点时如何更改URL?

33

默认情况下,如果我的网站中有锚点,则单击链接时(即www.mysite.com/#anchor),地址栏上的URL会更改。

当我滚动到锚点时,是否可以立即更改地址栏中的URL?或者当我点击新锚点时,地址栏上的URL会更改,而我有一个包含多个锚点的长文档?

6个回答

42
尝试使用这个jQuery插件:Scrollorama。它有很多很酷的功能,而且你可以使用window.location.hash来更新浏览器的哈希值。
或者,您可以添加一个“滚动”事件以检查是否到达锚点。
这是一个可用的示例:http://jsfiddle.net/gugahoi/2ZjWP/8/ Example:
$(function () {
    var currentHash = "#initial_hash"
    $(document).scroll(function () {
        $('.anchor_tags').each(function () {
            var top = window.pageYOffset;
            var distance = top - $(this).offset().top;
            var hash = $(this).attr('href');
            // 30 is an arbitrary padding choice, 
            // if you want a precise check then use distance===0
            if (distance < 30 && distance > -30 && currentHash != hash) {
                window.location.hash = (hash);
                currentHash = hash;
            }
        });
    });
});

3
太棒了!我在我的项目中使用了一个派生版本。然而,我们发现每次哈希值更改时会导致“滚动跳跃”,因此我们使用historyAPI解决了这个问题。如果(history.pushState) { history.pushState(null, null, "#"+hash); } else { window.location.hash = '#myhash'; } - Prashant
链接已失效,项目已更新,新版本在此处:https://scrollmagic.io/ - Binyomin

4

location.hash更加方便。 - Jonathan de M.
4
您应该在回答中包含关键部分;链接在互联网上容易失效(是的,我知道链接腐烂是Tim BL的小怪癖)。 - Lawrence Dol

2
您可以绑定到jQuery滚动事件(http://api.jquery.com/scroll/),并在每次调用回调时检查用户已滚动多远的文档,通过检查这个值:.scrollTop(http://api.jquery.com/scrollTop/),并通过操作location.hash对象(http://www.w3schools.com/jsref/prop_loc_hash.asp)来设置锚点。
代码如下:
// Checks if the passed element is visible on the screen after scrolling
// source: https://dev59.com/FHRB5IYBdhLWcg3w3K4J
function isScrolledIntoView(elem) {
  var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

$('#document').scroll(function(e) {
  var anchors = $('.anchor');
  for (var i = 0; i < anchors.length; ++i) {
    if (isScrolledIntoView(anchors[i])){
      var href = $(anchors[i]).attr('href');
      location.hash = href.slice(href.indexOf('#') + 1);
      break;
    }
  }
});

“如果在选择锚点后对其进行排序,您可以更加精确地设置第一个可见的锚点。”

嗨,乔治,谢谢你分享这个。你能否发布一个与上面代码配合使用的示例HTML标记呢? - Advanced
当然。这是一个例子:http://jsfiddle.net/7d5qU/10/。它应该可以工作,但我无法证明,因为jsfiddle隐藏了内部url... - Georgi Atsev

2
  1. 将处理程序绑定到jquery滚动事件
  2. 使用此jquery脚本检查锚点是否当前在屏幕上可见。
  3. 使用pushstate或设置位置(可能会导致跳转)

2

纯JS版本

在研究如何根据HTML部分元素在屏幕上的位置更新URL时,我一直找到这个主题,所以我希望这是一个好地方发布这个。

此函数循环遍历HTML部分元素。

        function updateFragId() {
        var len = sections.length;
          for (var i = 0; i < len; i++) {
            var id = sections[i].id;

收集相对于视口的垂直滚动位置。

            var rect = sections[i].getBoundingClientRect().y;

将这两个数组转换为一个对象

            var pageData = {id:id, rect:rect};

在代码触发之间设置一个范围。这里的范围是当部分元素的顶部在-200px至400px之间时触发。

            if (pageData.rect > -200 && pageData.rect < 400) {

为确保不会向浏览器发送过多事件,只需通过检查pageData.id和location.hash是否已匹配来确保只运行一次即可。

        if (pageData.rect > -100 && pageData.rect < 100) {
            if (pageData.id !== location.hash.substr(1)) {
                fragmentId = pageData.id;
                setActiveLink(fragmentId);
              } else {
                return;
            }
          }
        }
      }

    window.addEventListener('scroll', updateFragId);

我在这段代码块上使用了一个去抖动器,并与另一个块一起设置活动链接。但这只是跟踪#锚点的方法。


1
这个网站通常不赞成只有代码的答案。您能否编辑您的答案,包括一些注释或解释您的代码?解释应该回答以下问题:它是做什么的?它是如何做到的?它在哪里?它是如何解决 OP 的问题的? - mypetlion
感谢您的反馈。已更新。 - Jef

1

我认为你需要做类似于这样的事情。尚未实践过。

var myElements = $("div.anchor"); // You target anchors
$(window).scroll(function(e) {
    var scrollTop = $(window).scrollTop();
    myElements.each(function(el,i) {
        if ($(this).offset().top > scrollTop && $(myElements[i+1]).offset().top < scrollTop) {
             location.hash = this.id;
        }
    });
});

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