如何在加载页面时禁用锚点跳转?

123

我认为这可能是不可能的,我会尽力解释清楚。

我有一个包含选项卡(使用jQuery控制)的页面,由以下代码控制:

我正在使用由另一个用户在以前的问题中提供的代码。

<script type="text/javascript">
    $(function() {

     $('html, body').animate({scrollTop:0}); // this is my "fix"

        var tabContent = $(".tab_content");
        var tabs = $("#menu li");
        var hash = window.location.hash;
     tabContent.not(hash).hide();
        if(hash=="") {
      $('#tab1').fadeIn();
     }
        tabs.find('[href=' + hash + ']').parent().addClass('active');

        tabs.click(function() {
            $(this).addClass('active').siblings().removeClass('active');
            tabContent.hide();
            var activeTab = $(this).find("a").attr("href");

            $(activeTab).fadeIn();
           return false;
        });

    });
</script>

当我直接访问“标签”页面时,这段代码效果很好。

然而,我需要从其他页面链接到单独的标签 - 为此,该代码获取window.location.hash,然后显示相应的标签。

由于有“return false”,所以页面不会因为锚点而“跳转”。

只有在点击事件触发时才会触发此事件。因此,如果我从其他任何页面访问我的“标签”,将会触发“跳转”效果。为了解决这个问题,我自动滚动到页面顶部,但我宁愿不要发生这种情况。

是否有任何办法在页面加载时模拟“return false”,防止出现锚点“跳转”?

希望这足够清楚。

谢谢

16个回答

154

您的修复方法不起作用吗?我不确定是否正确理解了问题 - 您有演示页面吗?您可以尝试:

if (location.hash) {
  setTimeout(function() {

    window.scrollTo(0, 0);
  }, 1);
}

编辑:已经在Windows上的Firefox、IE和Chrome中测试通过。
编辑 2:将setTimeout()移动到if块内,感谢 @vsync。


2
英文原文:hero! Yes, my "fix" did work, but the page would "scroll" (as my code told it to), and I would rather it didn't scroll.你的代码完美地运行了。我之前没有注意到 ScrollTo 函数——它是否真的是必要的?似乎只用 window.scrollTo(0, 0) 就可以很好地工作了。 - Ross
3
我在一个空页面上使用Firefox尝试了一下,没有使用setTimeout时它并不总是有效。如果已经在jQuery的$(function() {中,您可能不需要它。您实际上不需要location.hash,但保留它很好,这样浏览器可能不需要做任何事情。它也会提醒您要使用scrollTo来实现什么效果! - dave1010
2
今天我遇到了同样的问题。实际上,我不得不在我的导航链接中添加哈希(与选项卡名称/ href 值相同)。最终,我给我的选项卡添加了一个 1 字符后缀,然后通过截取 1 个字符的值(str.slice(0,-1))将它们与 window.location.hash 进行比较。这样哈希就不同了,也不会出现跳转问题。 - developer10
1
if 应该在外面,而不是里面。此外,间隔的最小值约为 10,因此 0 或 1 与 10 相同,具体取决于浏览器。 - vsync
2
这并不会阻止浏览器跳转到哈希标签,你必须放置一个空的哈希标签来防止“跳动”,请参见我的答案:https://dev59.com/uHA65IYBdhLWcg3wvhTi#29823913 - Larzan
显示剩余6条评论

54

请看我在这里的回答:Stackoverflow 答案

关键是立即删除井号并将其值存储供自己使用:

重要的是,不要将该部分代码放在 $() 或 $(window).load() 函数中,因为那时已经太晚了,浏览器已经转到标签。

// store the hash (DON'T put this code inside the $() function, it has to be executed 
// right away before the browser can start scrolling!
var target = window.location.hash,
    target = target.replace('#', '');

// delete hash so the page won't scroll to it
window.location.hash = "";

// now whenever you are ready do whatever you want
// (in this case I use jQuery to scroll to the tag after the page has loaded)
$(window).on('load', function() {
    if (target) {
        $('html, body').animate({
            scrollTop: $("#" + target).offset().top
        }, 700, 'swing', function () {});
    }
});

1
我在使用max-height overflow-y属性时遇到了一个FF的bug,当我在一个非常长的列表上使用它时,FF会滚动到隐藏节点所在的dom位置。这段代码仅使用了实际代码的前三行(不包括注释),并且已经解决了我的FireFox问题。 - JQII
这正是我一直在寻找的。稍作修改以适应我的需求,但比滚动回顶部要好得多的解决方案。 - Jeff Sterup
1
如果您在页面加载后遇到浏览器滚动到原始加载滚动位置的问题,您可以使用现在广泛支持的history.scrollRestoration。请参见此答案https://dev59.com/D2Up5IYBdhLWcg3wVWYF#45758297。 - Gavin

12

我使用了dave1010的解决方案,但是当我将它放在$().ready函数中时,它有点卡顿。 所以我这样做了:(不在$().ready中)

    if (location.hash) {               // do the test straight away
        window.scrollTo(0, 0);         // execute it straight away
        setTimeout(function() {
            window.scrollTo(0, 0);     // run it a bit later also for browser compatibility
        }, 1);
    }

12
  1. 如果地址栏中有http://site.com/#abc哈希标识,并且id="abc"的元素可见,则浏览器会跳转到<element id="abc" />。因此,您应该默认隐藏该元素:<element id="anchor" style="display: none" />。如果页面上没有可见的id=hash元素,则浏览器不会跳转。

  2. 创建一个脚本来检查URL中的哈希标识,然后查找并显示相应的元素(默认情况下隐藏)。

  3. 通过将onclick事件绑定到链接并指定return false;作为onclick事件的结果来禁用默认的“类似哈希标识的链接”行为。

当我实现选项卡时,我写了类似以下的代码:

    <script>
    $(function () {         
        if (location.hash != "") {
            selectPersonalTab(location.hash);
        }
        else {
            selectPersonalTab("#cards");
        }
    });

    function selectPersonalTab(hash) {
        $("#personal li").removeClass("active");
        $("a[href$=" + hash + "]").closest("li").addClass("active");
        $("#personaldata > div").hide();
        location.hash = hash;
        $(hash).show();
    }

    $("#personal li a").click(function (e) {
        var t = e.target;
        if (t.href.indexOf("#") != -1) {
            var hash = t.href.substr(t.href.indexOf("#"));
            selectPersonalTab(hash);
            return false;
        }
    });
</script>

12

还有其他跟踪当前标签页的方法,例如设置cookie、在隐藏字段中设置值等。

如果您不希望页面在加载时跳动,我建议您使用其中一种其他选项而不是哈希,因为使用哈希的主要原因是允许您阻止您想要的内容。

另一个要点是,如果哈希链接与文档中的<标签>名称不匹配,则页面不会跳动。因此,如果您仍想使用哈希,请操作内容以使<标签>名称不同。如果您使用一致的前缀,仍然可以使用JavaScript在它们之间跳转。

希望这有所帮助。


2
好的建议。不要忘记尝试在关闭JS / CSS的情况下保持页面可用/可访问性。 - dave1010

10

没有一个答案对我来说足够好,我发现在某些解决方案中页面会跳转到锚点然后回到顶部,有些答案根本不起作用,可能是因为时间变化了。希望我的函数能对某些人有所帮助。

/**
 * Prevent automatic scrolling of page to anchor by browser after loading of page.
 * Do not call this function in $(...) or $(window).on('load', ...),
 * it should be called earlier, as soon as possible.
 */
function preventAnchorScroll() {
    var scrollToTop = function () {
        $(window).scrollTop(0);
    };
    if (window.location.hash) {
        // handler is executed at most once
        $(window).one('scroll', scrollToTop);
    }

    // make sure to release scroll 1 second after document readiness
    // to avoid negative UX
    $(function () {
        setTimeout(
            function () {
                $(window).off('scroll', scrollToTop);
            },
            1000
        );
    });
}

到目前为止,我找到的最佳解决方案。实际上,我看到了很多。 - MarkSkayff
谢谢你!这是我尝试了几个小时后唯一有效的解决方案,但对我来说最好的部分是我不必删除哈希。 - Chris Vecchio
如果滚动条在页面加载时已经在页面顶部,则此方法无效,它会像往常一样向下滚动,并在页面完成后跳回到顶部。有人知道为什么会出现这种情况吗? - robgha01
@robgha01请确保该函数尽快执行,不要等待任何事件。这是错误的写法:$(document).ready(function () { preventAnchorScroll(); });,只需在JavaScript的开头调用该函数即可。我已经测试过了,在Chrome、Firefox和Opera中都可以正常工作。 - kdmitry

6

当使用锚点时,保持滚动条位置的一种简单但不规范的解决方案(如果您仍然想使用锚点进行滚动跳转,则没有用处,但对于深度链接非常有用):

.elementsWithAnchorIds::before {
   content: "";
   display: block;
   height: 9999px;
   margin-top: -9999px; //higher thin page height
}

如此聪明! - duhaime
我喜欢这个。 - Larry Williamson
到目前为止仍然是最好的答案,其他答案会导致闪烁。 - Marián Kadaňka

3

虽然已经接受的答案确实有效,但我发现有时候在包含大图像的页面上使用该方法会导致滚动条疯狂跳动。

 window.scrollTo(0, 0);

这可能会对用户造成很大的干扰。

最终我采用的解决方案其实非常简单,那就是在目标上使用一个不同于location.hash中使用的ID。

例如:

以下是来自其他页面的链接:

<a href="/page/with/tabs#tab2">Some info found in tab2 on tabs page</a>

当然,如果选项卡页面上有一个ID为tab2的元素,窗口加载时会跳转到该元素。

因此,您可以将一些内容附加到ID中以防止其发生:

<div id="tab2-noScroll">tab2 content</div>

然后在javascript中,您可以将"-noScroll"附加到location.hash

<script type="text/javascript">
    $(function() {

        var tabContent = $(".tab_content");
        var tabs = $("#menu li");
        var hash = window.location.hash;


     tabContent.not(hash + '-noScroll').hide();                           
        if(hash=="") {       //^ here
      $('#tab1-noScroll').fadeIn();
     }
        tabs.find('[href=' + hash + ']').parent().addClass('active');

        tabs.click(function() {
            $(this).addClass('active').siblings().removeClass('active');
            tabContent.hide();
            var activeTab = $(this).find("a").attr("href") + '-noScroll'; 
                                                               //^ and here

            $(activeTab).fadeIn();
           return false;
        });

    });
</script>

2

因为我使用了锚链接进行CSS弹出,所以我的做法是:

一旦点击,首先保存页面的pageYOffset,然后将ScrollTop设置为该值:

$(document).on('click','yourtarget',function(){
        var st=window.pageYOffset;
        $('html, body').animate({
                'scrollTop' : st
            });
});

在尝试了其他解决方案之后,这是对我有效的一个。在我的情况下,我正在处理的网站使用#在URL中加载结账的特定部分。与其修改URL中哈希的结账功能,我选择使用了这个方法。谢谢。 - chris c

1

我认为我已经找到了一种不需要重新编写功能的UI选项卡方法。到目前为止,我还没有发现任何问题。

    $( ".tabs" ).tabs();
    $( ".tabs" ).not(".noHash").bind("tabsshow", function(event, ui) { 
        window.location.hash = "tab_"+ui.tab.hash.replace(/#/,"");
        return false;
    });

    var selectedTabHash = window.location.hash.replace(/tab_/,"");
    var index = $( ".tabs li a" ).index($(".tabs li a[href='"+selectedTabHash+"']"));
    $( ".tabs" ).not(".noHash").tabs('select', index);

所有都在 ready 事件中。它为哈希值加上 "tab_" 前缀,但可以在单击和页面加载时一起使用。


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