如何用堆栈来保存和恢复滚动条位置

问题背景

在单页应用中,翻页一般通过display:none将先前的面板(一般就是个div容器)隐藏,然后将本次需要展现的面板设置成display:block(当然,还可能加点css切换动画,不过不影响我们本次的讨论结果,故不予关注),一般情况下,这样的处理方式是没啥问题的,不过如果之前的面板本身有滚动条,那么跳转到新面板之后再返回到原先面板就会导致滚动条位置直接变成0,这主要是当元素的display为none时,元素不占据位置,等到display非none的时候才会被重新布局,渲染。

我们以jq.ui(一个用于构建jqMobi应用的用户界面库)为例说明下怎么解决单页应用中切换页面导致的滚动条位置信息丢失问题

思路

在老页面被display:none之前用一个堆栈存储下当前页面的滚动条位置,然后在用户点击浏览器返回按钮的时候取出栈顶记录的滚动条位置信息并调用window.scroll滚动到指定位置即可。

基于jq.ui的实例

1、在jq.ui源码中页面切换之前手动触发个事件(用于在自己的代码中捕捉此事件并记录老页面滚动条位置信息)

/*在老的panel被display:none之前触发beforeHideOldPanel事件,
*用于记录当前滚动条位置,以便于返回上一页时滚动到指定位置*/
jq(oldDiv).trigger('beforeHideOldPanel');
复制代码

2、在页面上监听第一步中触发的beforeHideOldPanel事件和popstate(浏览器回退事件)以及loadpanel(加载面板事件),当beforeHideOldPanel事件被触发且当前不在回退时记录滚动条位置,当loadpanel事件被触发且当前正在回退时从堆栈中取出滚动条位置并调用window.scroll手动滚动到指定位置

// 由于jq.wow.js中通过display:none方式切换面板,导致老的panel滚动条信息丢失
// (display:none元素无高度),点击返回上一页时会自动定位到顶部
// 此处通过一个简单的堆栈记录老页面的滚动条信息,退回上一页时手动调用window.scroll滚动到指定位置
function resetScrollWhenPopstate() {
    //借助数组实现个简单的堆栈
    var scrollStack = {
        list: [],
        push: function (obj) {
            this.list.push(obj);
        },
        pop: function () {
            return this.list.pop();
        }
    };
    
    $('.panel').on('beforeHideOldPanel', function (e) {
        // 仅非回退时才记录滚动条位置
        if (!isPopStating) {
            scrollStack.push({
                oldPageId: e.currentTarget.id,
                oldScrollTop: document.documentElement.scrollTop || document.body.scrollTop
            });
        }
    }).on('loadpanel', function (e) {
        // 仅回退页时才恢复滚动条位置
        if (isPopStating) {
            var obj = scrollStack.pop();
            if (obj && obj.oldPageId == e.currentTarget.id) {
                window.scroll(0, obj.oldScrollTop);
            }
        }
    });
    
    // 标示是否正在回退
    var isPopStating = false;
    window.addEventListener('popstate', function () {
        isPopStating = true;
        setTimeout(function () {
            isPopStating = false;
        }, 200);
    });
}
复制代码

总结

看似简单的堆栈其实还是有挺大用处的,算法和数据结构这东西看来还是需要学习学习(@ο@) 哇~

請你幫我檢查爲什麽我變動#menu 向左移動,卻不懂,是由衝突嗎? <style> /* CSS 样式 */ body { font-family: "Microsoft YaHei", sans-serif; background-color: #f5f7fa; margin: 0; padding: 0; } #main { height: 500px; /*设定主体内容高度*/ overflow-y: scroll; /*添加滚动条*/ } a { text-decoration: none; color: #000; } #menu { display: flex; justify-content: space-between; align-items: center; padding: 10px; background-color: #fff; box-shadow: 0 2px 4px rgba(0,0,0,.1); background-color: #333; color: #fff; width: 200px; height: 500px; } #menu ul { list-style-type: none; margin: 0; padding: 0; } #menu li a { display: block; color: #fff; padding: 10px 20px; text-decoration: none; } #menu li a:hover { background-color: #555; } #main { max-width: 1000px; margin: auto; padding: 20px; background-color: #fff; box-shadow: 0 2px 4px rgba(0,0,0,.1); position: fixed; top: 0; right: 0; } h1 { margin-top: 0; } form { display: flex; flex-wrap: wrap; margin-bottom: 20px; } label { flex-basis: 120px; line-height: 32px; margin-right: 20px; } input[type="date"], input[type="text"] { border: 1px solid #ccc; border-radius: 3px; padding: 6px 12px; outline: none; } input[type="submit"] { border: none; border-radius: 3px; padding: 6px 12px; background-color: #007bff; color: #fff; cursor: pointer; } table { width: 100%; border-collapse: collapse; margin-bottom: 20px; } th, td { border: 1px solid #ccc; padding: 8px; text-align: center; } th { background-color: #f5f7fa; font-weight: bold; } tr:nth-child(even) td { background-color: #f5f7fa; } canvas { max-width: 100%; height: auto !important; } </style>
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值