按下后退按钮时如何保留可滚动区域的滚动位置?

Posted

技术标签:

【中文标题】按下后退按钮时如何保留可滚动区域的滚动位置?【英文标题】:How can I retain the scroll position of a scrollable area when pressing back button? 【发布时间】:2015-05-26 00:48:19 【问题描述】:

我在一个大的可滚动 div 中有一个很长的链接列表。每次当用户单击链接然后单击后退按钮时,它都会从 div 的最顶部开始。它对我们的用户不友好。按下后退按钮时有什么方法可以让浏览器滚动到上一个位置?

非常感谢!

【问题讨论】:

查看此链接...***.com/questions/2009029/… 将位置存储在 cookie 中,然后使用 cookie 将页面滚动到确切位置。 【参考方案1】:

在页面卸载期间,获取滚动位置并将其存储在本地存储中。然后在页面加载期间,检查本地存储并设置滚动位置。假设你有一个 id 为 element 的 div 元素。如果是页面,请更改选择器:)

$(function() 
   $(window).unload(function() 
      var scrollPosition = $("div#element").scrollTop();
      localStorage.setItem("scrollPosition", scrollPosition);
   );
   if(localStorage.scrollPosition) 
      $("div#element").scrollTop(localStorage.getItem("scrollPosition"));
   
);

【讨论】:

谢谢!这很好,但仍然是一件小事。点击返回时,浏览器初始从顶部开始,0.5秒后跳转到该位置。有什么办法可以缩短时间流逝,让它看起来更流畅? 这是因为代码是在加载完dom之后才执行的。这就是为什么会有延迟。而不是将代码放在加载的 domContent 中。您可以尝试 $("div#element").load(function() ) 并将元素放在文档就绪处理程序之外。 另外,如果用户向下滚动页面,然后离开页面,然后再次返回页面,这对他来说应该是一个新的开始,所以应该从顶部开始。但现在它也记住了之前的位置。有什么办法可以防止这种情况? :) 再添加一个条件,检查$(window).scrollTop();看看它是否在 650 以上。在这种情况下,不要将 scrollPosition 存储在本地存储中:) 感谢@mohamedrias 你拯救了我的一天!【参考方案2】:

如果后退按钮是一种历史后退按钮window.history.back() 那么您正在寻找的是默认浏览器功能。所以你不必担心。

如果您的后退按钮实际上通过链接或表单指向应用程序中的某个 URL,那么您必须手动处理。

对于解决方案,您可以使用 cookie 来存储您的页面滚动值。每次用户在您的页面上滚动时,请将该页面的滚动值保存到 cookie。额外的工作应用于手动 cookie 管理。

window.onScroll = function()
    document.cookie="pageid=foo-"+window.scrollY+";";

此cookie值可用于设置页面访问时页面的滚动值。

window.scroll(0,cookievalue);

【讨论】:

【参考方案3】:

我在一个简单的用户界面中遇到了同样的问题,该界面由一个固定的菜单 div 和一个滚动的文档 div(下面的代码示例中的“pxeMainDiv”)组成。以下解决方案在 Chrome 47.0.2526.106 m 和 Firefox 43.0.3 中对我有用。 (我的应用程序是在内部使用的,我不需要迎合旧版本的 IE)。

$(document).ready(function()
    if (history.state) 
       $("#pxeMainDiv").scrollTop(history.state.data);
    
    $("#pxeMainDiv").scroll(function() 
       var scrollPos = $("#pxeMainDiv").scrollTop();
       var stateObj =  data: scrollPos ;
       history.replaceState(stateObj, "");
    );
);

在 div 滚动事件上,div 的滚动位置存储在浏览器历史对象内部的状态对象中。按下后退按钮后,在文档就绪事件上,div 的滚动位置恢复为从 history.state 对象检索到的值。

此解决方案适用于任意长链接链的反向导航。

此处的文档:https://developer.mozilla.org/en-US/docs/Web/API/History_API

【讨论】:

【参考方案4】:

我认为我们应该保存每页的滚动数据,而且我们应该使用会话存储而不是本地存储,因为会话存储只影响当前选项卡,而本地存储在所有选项卡和同源窗口之间共享

$(function () 
            var pathName = document.location.pathname;
            window.onbeforeunload = function () 
                var scrollPosition = $(document).scrollTop();
                sessionStorage.setItem("scrollPosition_" + pathName, scrollPosition.toString());
            
            if (sessionStorage["scrollPosition_" + pathName]) 
                $(document).scrollTop(sessionStorage.getItem("scrollPosition_" + pathName));
            
        );

【讨论】:

是的——这非常重要。在 sessionStorage 中保存路径名正是这里需要的。【参考方案5】:

当使用window.history.back() 时,这实际上是默认浏览器功能as user SD. has pointed out。

在我目前正在构建的网站上,我希望将公司的徽标反向链接到索引页面。从 jQuery 3 开始,$(window).unload(function() 应该被重写为 $(window).on('unload', function()。我的代码看起来像这样(使用 Kirby CMS 的 php 语法):

<?php if ($page->template() == 'home'): ?>

<script>

$(function() 
 $(window).on("unload", function() 
    var scrollPosition = $(window).scrollTop();
    localStorage.setItem("scrollPosition", scrollPosition);
 );
 if(localStorage.scrollPosition) 
    $(window).scrollTop(localStorage.getItem("scrollPosition"));
 
);

</script>

【讨论】:

【参考方案6】:

使用History api,您可以使用scrollRestoration 并阻止浏览器重置滚动位置。

在这里阅读。 https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration

【讨论】:

【参考方案7】:

对于任何来自 react 或任何类似于 react 路由器的人,这里有两个简单的功能:

export function saveScrollPosition(context: any) 
  let path = context.router.route.location.pathname;
  let y = window.scrollY;
  sessionStorage.setItem("scrollPosition_" + path, y.toString());


export function restoreScrollPosition(context: any) 
  let path = context.router.route.location.pathname;
  let y = Number(sessionStorage.getItem("scrollPosition_" + path));
  window.scrollTo(0, y);

【讨论】:

很高兴知道如何使用这些。【参考方案8】:

/* 使用以下代码恢复单个项目的滚动位置并将焦点设置到最后单击的项目。 */

(function ($)


    if (sessionStorage)
        $.fn.scrollKeeper = function (options)
        
            var defauts =
            
                key: 'default'
            ;
            var params = $.extend(defauts, options);

            var key = params.key;
            var $this = $(this);

            if (params.init === true)
            
                var savedScroll = sessionStorage.getItem(key);

                if (typeof savedScroll != 'undefined')
                
                    var int_savedScroll = parseInt(savedScroll);
                    if (int_savedScroll > 0)
                        $this.scrollTop(int_savedScroll);

                    setTimeout(function ()
                    
                        var selectorFocus = sessionStorage.getItem(key + "-focus");
                        if (selectorFocus && selectorFocus != "")
                            $(document.querySelector(selectorFocus)).focus();
                    , 100, key);
                
            

            window.addEventListener("beforeunload", function () 
            
                sessionStorage.setItem(key, $this.scrollTop());
                if (document.activeElement)
                
                    var selectorFocus = elemToSelector(document.activeElement);

                    if (selectorFocus)
                        sessionStorage.setItem(key + "-focus", selectorFocus);
                    else
                        sessionStorage.setItem(key + "-focus", "");
                
                else
                    sessionStorage.setItem(key + "-focus", "");

            );
        ;


    function elemToSelector(elem)   /* written by Kévin Berthommier */
    
        const 
            tagName,
            id,
            className,
            parentNode
         = elem;

        if (tagName === 'html') return 'HTML';

        let str = tagName;

        str += (id !== '') ? `#$id` : '';

        if (className)
        
            const classes = className.split(/\s/);
            for (let i = 0; i < classes.length; i++)
            
                if(typeof classes[i] === 'string' && classes[i].length > 0)
                    str += `.$classes[i]`;
            
        

        let childIndex = 1;

        for (let e = elem; e.previousElementSibling; e = e.previousElementSibling)
        
            childIndex += 1;
        

        str += `:nth-child($childIndex)`;

        return `$elemToSelector(parentNode) > $str`;
    

)(jQuery);

/* 用法:

$('#tab1div').scrollKeeper( key: 'uniq-key1', init: true );

如果您不需要恢复滚动位置(例如重启),而只需要保存滚动位置以供下次使用,请使用:

$('#tab1div').scrollKeeper( key: 'uniq-key1', init: false ); */

【讨论】:

以上是关于按下后退按钮时如何保留可滚动区域的滚动位置?的主要内容,如果未能解决你的问题,请参考以下文章

如何在按钮按下时在集合视图中滚动(水平)?

单击后退按钮时,React-router 滚动到顶部

单击后退按钮但不离开页面时防止自动滚动?

在后退按钮上,为啥 Firefox 直接跳到我以前的滚动位置而不是动画

如何将 UIView 锚定到屏幕上的特定位置并在滚动时将其保留在那里

从滚动视图打开子视图