JQuery-在加载并直接转到带有锚点的URL时获取偏移量

JQuery - Get an offset when loading and going directly to a URL with anchor

本文关键字:URL 偏移量 获取 加载 JQuery-      更新时间:2023-11-27

我尝试添加以下功能:当我键入带有锚的URL时,我希望直接在锚上。我的问题是,我有一个固定的头,并且我当前的JQuery代码没有考虑我放置的偏移量(55,即the height of header)。

以下是代码片段:

 if ($(location.href.split("#")[1])) {
    var target = $('#'+location.href.split("#")[1]);
    if (target.length) {
       var hash = this.hash; 
       $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300, function() {
       location.hash = hash;
       });
    }
  } 

此代码片段位于[ancher.js][1]脚本中。

我被很好地重定向到锚,但无论我采用什么偏移值,最终结果都不会考虑到这一点,因此在加载页面后,锚名称会被固定的标题隐藏。

如果有人能帮我解决这个问题,

提前谢谢。

ps:我只想让它在Firefox和Chrome上运行。

更新

看来解决方案可能来自这个环节。

为此,我必须在<a name="..."></a>标记之前插入一个带有class='direct_anchor'<span>标记(带有.beforeJquery函数),因此我在CSS中包含以下规则:

.direct_anchor {
display: block;
height: 55px; // Height of fixed header
margin-top: -55px; 
visibility: hidden;
}

最后,这里是我直接在地址栏中键入一个具有哈希扩展名的URL的情况的代码片段:

var target = $('[name="'+location.href.split("#")[1]+'"]');
  var hash = location.href.split("#")[1];
  if (target.length) {
    location.hash = hash;
    $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300);
    target.before( "<span class='direct_anchor'></span>" );
  }

不幸的是,我无法使其工作,class='direct_anchor'CSS规则似乎没有应用于span标记。

我不是Jquery的专家,有人能看出问题出在哪里吗?

谢谢你的帮助。

我调试后发现,在重新加载时,脚本不会在if语句中执行。

$(window).bind("load", function () {
      $('a[href*="#"]:not([href="#SECTION"]):not([href*="wikipedia"]):not([href*="mjx-eqn"])').click(function(event) {
        event.preventDefault();
        if (location.pathname.replace(/^'//,'') == this.pathname.replace(/^'//,'') && location.hostname == this.hostname) {
        var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        var hash = this.hash; 
        $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300, function() {
          href = window.location.href;
          history.pushState({page:href}, null, href.split('#')[0]+hash);
        });
        return false;
      }
      }
      });
      $(window).bind('popstate', function(event) {
        var state = event.originalEvent.state;
        var target = window.location.href.split('#');
        var href = target[0];
        if (state) {
          $('html,body').animate({ scrollTop: 0 }, 300, function() {
            history.replaceState({}, null, href);
          });
        }
      });
      // code changed here 
      var target = $("[name='"+location.href.split("#")[1]+"']");
      if (target.length) {
        $('html,body').animate({ scrollTop: target.offset().top-55},300);
      }
    });

请注意,您可以使用name而不是id作为选择器来获取元素。这是一个现在已经解决的问题。我已经通过调试进行了检查,所以不能确定它,但它在chrome中运行良好。我无法签入firefox,因为我不知道如何使用调试器编辑脚本。

尝试在动画之前更改位置哈希

location.hash = this.hash;
$('html, body').animate({scrollTop: target.offset().top -55 }, 300);

在动画之后更改它会导致页面跳回没有偏移的目标。

有趣的是,几天前我在博客上也遇到了同样的问题。问题不在于代码,而在于浏览器实现,它会等待一段时间和/或多次尝试将哈希与页面上的id匹配。在我的例子中,id是用Javascript生成的,浏览器仍然会访问它们。您的代码可能会被执行,然后浏览器无论如何都会转到该点。

我的解决方案包括插入一个不可见的元素,该元素在散列中实际携带id,并使其位置相对且顶部为-50像素。作为一个通用的解决方案,我认为你唯一的(丑陋的)选择是检查id与哈希相同的元素的偏移量,并且只在检测到浏览器移动它或超时后滚动容器。

这是一个解决方案的演示(在jsfiddle中不起作用)。请注意,在这里我会立即执行脚本,因此如果页面加载需要更长的时间,您可能需要增加超时时间。另一个解决方案是在DOMready上运行它,但我认为这会给您带来尴尬的延迟。

<html>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>
<style>
header {
  height:50px;
  width:100%;
  background:wheat;
  position:fixed;
  top:0;
}
#target {
    color:red;
}
#topHalf, #bottomHalf {
    margin-left:20%;
    width:50%;
    height:2000px;
    background-color:gray;
}
</style>
<script>
(function() {
    if (!location.hash) return;
    var timeout=1000; //1 second. You may want to wait more
    var done=false;
    var interval=setInterval(function() {
        var elem=document.getElementById(location.hash.substr(1));//hash can be '#id,div.aClass' or similar
        if (!elem) return;
        elem=$(elem);
        var ofs=elem.offset();
        if (!ofs||!ofs.top) return;
        timeout-=100; //interval time
        var scrollY=$(window).scrollTop(); //window to get scrollTop, not html,body which yields 0 on Chrome
        if (Math.abs(ofs.top-scrollY)<55) { //header size, just to be sure
            done=true; // if we are close, then probably the browser did its thing
            clearInterval(interval);
            $('html,body').animate({ scrollTop: ofs.top - 55 }, 300);
        }
        if (timeout<=0) { //otherwise, just do it on timeout
            clearInterval(interval);
            if (!done) $('html,body').animate({ scrollTop: ofs.top - 55 }, 300);
        }
    },100);
})();
</script>
<header></header>
<content>
<div id="topHalf"></div>
<a id="target">This is the target</a>
<div id="bottomHalf"></div>
</content>
<script>
var k=0;
for (var i=0; i<100000000; i++) {
    //some slow running code
    k+=Math.random();
}
document.write('K:',k); // using k so that it doesn't get optimized away
</script>
  End
</html>

只需在h4之上为锚点创建一个div。例如:

<div id="simulation"></div>

带有:

#simulation {
 position: relative;
 bottom: 50px;
}

我不确定JavaScript是否是最好的方法。如果你的标题是固定的,你只需要在CSS的主要内容包装上添加55像素的填充即可。