防止刷新时浏览器自动滚动

114

如果您在页面a上滚动并刷新页面,则该页面将在您离开的位置处刷新。这很好,但是在URL中存在锚点位置的页面上也会发生这种情况。例如,如果您单击链接http://example.com/post/244#comment5,并在浏览后刷新页面,则您不会在锚点处,页面会出现跳动。是否有任何方法使用javascript来防止这种情况?以便无论如何,您始终可以导航到锚点。


你需要使用jQuery解决方案还是纯JS可以? - mrtsherman
9个回答

162

在Chrome浏览器中,即使您将scrollTop强制设置为0,它仍会在第一个滚动事件后跳跃。

您应该将滚动绑定到以下内容:

$(window).on('beforeunload', function() {
    $(window).scrollTop(0);
});
因此,浏览器被欺骗认为在刷新之前的起始位置。

5
如果您不想费时间滚动页面,这个答案比被接受的答案更有用。 - Dan Abramov
2
这在Chrome 33中无法完成任务。我的意思是,在加载新页面之前,它确实会滚动到顶部。然而,浏览器仍然以某种方式记住了先前的滚动位置,并执行相同的自动滚动到该位置。 - Haralan Dobrev
32
对于非jQuery实现: window.onbeforeunload = function(){ window.scrollTo(0,0); } 翻译为:在没有使用jQuery的情况下: window.onbeforeunload = function(){ window.scrollTo(0,0); } - ProfNandaa
6
为什么你选择了 'beforeunload' 事件而不是 'unload'。我的测试显示,使用后者可以避免页面在浏览器真正卸载之前跳转到页面顶部。 - Aleksandr Zonov
1
在Chrome 59中,它会在页面刷新后自动滚动到顶部。如果我不想让Chrome自动滚动到任何位置,并通过使用JS到达页面上的特定位置,这仍然无法解决问题,因为我通过JS滚动到的任何位置都将被Chrome的自动滚动覆盖,并且之后它会滚动到页面顶部。 - Tom Pažourek
显示剩余5条评论

126

要禁用自动滚动恢复,只需将此标签添加到头部部分。

<script>history.scrollRestoration = "manual"</script>

支持所有现代浏览器


3
如果在IE/Edge中有这个选项的话,这将是最佳答案。不过你可以在这里投票以实现它:https://wpdev.uservoice.com/forums/257854-microsoft-edge-developer/suggestions/17257562-implement-history-scrollrestoration - pjk_ok
10
这应该是2019年的正确答案。其他方法都不是100%可行。 - Limbo
5
可以确认这是最佳解决方案。其他方案在移动Safari上无法正常工作,可能会有些卡顿。而这个方案完美地运行。 - user3330820
确实,这是最好的答案。当您刷新页面时,beforeunload功能将在页面刷新之前跳转到顶部,因此看起来不太好,反正谁还关心IE呢? - Xequtor
这就是答案。截至2020年,它可以在Edge上运行,因此适用于所有现代浏览器。https://caniuse.com/mdn-api_history_scrollrestoration - Yarin
大家都在推荐其他方法 - 各种形式的scrollTo(0,0)。但对我来说都没用。这个一开始就完美地解决了问题。谢谢! - purplefloyd

26

经过多次尝试,我终于成功了。在这里anzo是正确的,因为使用beforeunload会使页面在用户重新加载页面或单击链接时跳转到顶部。所以unload是明显的方法。

$(window).on('unload', function() {
   $(window).scrollTop(0);
});

Javascript方法(感谢ProfNandaa):

window.onunload = function(){ window.scrollTo(0,0); }

编辑:2015年7月16日

即使使用unload事件,Firefox仍存在跳转问题。


3
这个解决方案比之前的 beforeunload 解决方案好得多,因为它可以防止在重新加载和单击锚点时跳转到页面顶部。 - BradGreens
1
@BradGreens 在现代Chrome浏览器中,当用户切换到其他标签页时,onunload事件也会被触发,这是意外的。onbeforeunload仍然是有效的解决方法。 - Telvin Nguyen
@TelvinNguyen 你能提供任何相关资源吗?我在 Google Chrome 72 上测试过,对我来说仍然可以正常工作。 - Janaka Dombawela
@JanakaDombawela 我所说的是:移动可能会导致问题的新标签页是不正确的。然而,您可以看到在此示例中,即使使用jQuery 1.9.1与jQuery 1.8.3,事件onunload也无法正确触发。onunload是不可靠的。 https://jsfiddle.net/6s4jhdug/3/(1.8.3) https://jsfiddle.net/frt45ue9/(1.9.1) - Telvin Nguyen

16

由于浏览器行为的更改,不再推荐使用此解决方案。请查看其他答案。

基本上,如果使用锚点,我们会绑定到窗口滚动事件。其主要思想是第一个滚动事件必须属于浏览器自动重新定位。当这种情况发生时,我们进行自己的重新定位,然后删除绑定的事件。这可以防止随后的页面滚动破坏系统。

$(document).ready(function() {
    if (window.location.hash) { 
        //bind to scroll function
        $(document).scroll( function() {
            var hash = window.location.hash
            var hashName = hash.substring(1, hash.length);
            var element;

            //if element has this id then scroll to it
            if ($(hash).length != 0) {
                element = $(hash);
            }
            //catch cases of links that use anchor name
            else if ($('a[name="' + hashName + '"]').length != 0)
            {
                //just use the first one in case there are multiples
                element = $('a[name="' + hashName + '"]:first');
            }

            //if we have a target then go to it
            if (element != undefined) {
                window.scrollTo(0, element.position().top);
            }
            //unbind the scroll event
            $(document).unbind("scroll");
        });
    }

});

我正在考虑的一个应该被考虑的用例是,如果用户在自动滚动发生之前滚动页面。据我回忆,自动滚动只会在页面完全加载后发生。如果用户在此之前滚动,则自动滚动将被取消。因此,您需要一些方法来区分用户启动的滚动和浏览器启动的滚动。我不知道如何做到这一点,但据我回忆,这是可能的。 - mrtsherman
1
哇塞!这是一个有趣的深夜问题。不过当我在办公桌上睡着时,我会告诉我的老板这是你的错。我只是快速修改了一下,删除了返回语句。这会干扰我为滚动事件添加的解绑操作。 - mrtsherman
1
如果页面加载后还有内容加载,它就无法工作;例如:有两个包含横幅的 div 将通过 Ajax 填充。 - Decebal
@FlashThunder - 谢谢Flash。这个之前一定是有效的,因为Chrome是我首选浏览器。我会根据josetapadas的答案更新我的回答。显然,Chrome现在需要绑定到不同的事件。再次感谢。 - mrtsherman
@FlashThunder - 实际上,我不知道是否有一种方法可以修改这个答案。Jose的答案是新的、正确的做法。我只会在我的答案中加注,并将我的解决方案保留在这里供参考。 - mrtsherman
显示剩余3条评论

4

这对我来说有效。

    //Reset scroll top

    history.scrollRestoration = "manual"

    $(window).on('beforeunload', function(){
          $(window).scrollTop(0);
    });

3

下面是一种更通用的方法。与其试图阻止浏览器滚动(或看起来像是跳转到顶部),我只需恢复页面上先前的位置。即,我将当前页面的y偏移量记录在localStorage中,在页面加载后滚动到该位置。

function storePagePosition() {
  var page_y = window.pageYOffset;
  localStorage.setItem("page_y", page_y);
}


window.addEventListener("scroll", storePagePosition);


var currentPageY;

try {
  currentPageY = localStorage.getItem("page_y");

  if (currentPageY === undefined) {
    localStorage.setItem("page_y") = 0;
  }

  window.scrollTo( 0, currentPageY );
} catch (e) {
    // no localStorage available
}

2
你可以在链接的结尾处加上 # ,这样页面就会自动滚动到顶部。
因为这种方法非常简单,所以适用于所有浏览器、移动设备和桌面设备。
$(document).ready(function() {
var url = window.location.href;
console.log(url);
if( url.indexOf('#') < 0 ) {
    window.location.replace(url + "#");
} else {
    window.location.replace(url);
}

});

// 这个代码加载的页面末尾带有#。


如果我直接在我的服务器上尝试这个,它就像魔术一样奏效。但是,我的CMS给了我标记错误。我无法弄清楚那是什么。 - alice
1
如果您正在使用WordPress,请将$更改为jQuery。 - Yala Yala Herzlin

0

这个完全正常。漂亮干净的JavaScript代码。

    var objDiv = document.getElementById("chatbox");
if ( window.history.replaceState ) {
  objDiv.scrollTop = objDiv.scrollHeight;

    window.history.replaceState( null, null, window.location.href );
}

-2

你应该能够做到。

在页面加载时,检查window.location.hash是否有值。如果有,获取与哈希值匹配的id元素。找到元素的位置(递归调用offsetTop/offsetLeft)然后将这些值传递给window.scrollTo(x, y)方法。

这样可以滚动页面到所需的元素。


3
这并不会阻止浏览器自动滚动。这就是这个问题所涉及的内容。 - Haralan Dobrev

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