jQuery中滚动场景下浏览器返回按钮逻辑失效问题排查
滚动触发锚点切换后返回按钮失效的解决方案
问题描述
需求逻辑如下:
- 访客进入网站时,地址栏添加第一个锚点
- 访客点击页面或滚动页面后,切换为第二个锚点
- 地址栏存在第二个锚点时,点击浏览器返回按钮需回到第一个锚点并弹出弹窗
当前点击触发的逻辑正常,但滚动触发时,点击返回按钮会直接离开网站,无法回到第一个锚点。原实现代码:
var isStartUserAction = false; window.location.href = methods.setAnchor(settings.initAnchor); $(document).on('touchend', function () { if (!isStartUserAction) { window.location.href = methods.setAnchor(settings.startLogicAnchor); isStartUserAction = true; } }).on('scroll', function () { if (!isStartUserAction) { window.location.href = methods.setAnchor(settings.startLogicAnchor); isStartUserAction = true; } }); window.onpopstate = function(event) { if (isStartUserAction && !isShowedModal) { methods.show(); } };
问题原因
- 滚动事件触发频率极高,直接修改
window.location.href会导致浏览器历史记录栈异常——可能多次重复添加历史条目,或覆盖初始锚点的历史记录。 - 直接修改
href的方式无法精准控制历史栈的层级,导致从第二个锚点返回时,没有第一个锚点的历史记录可回溯,直接跳转到进入网站前的页面。
解决方案
改用history.pushState管理历史记录,同时给滚动事件添加防抖处理,避免频繁触发逻辑:
var isStartUserAction = false; var isShowedModal = false; // 初始化第一个锚点,将状态存入历史栈 history.pushState({ anchor: settings.initAnchor }, '', methods.setAnchor(settings.initAnchor)); // 防抖函数:限制滚动事件触发频率 function debounce(func, wait) { let timeout; return function() { const context = this; const args = arguments; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } $(document).on('touchend', function () { if (!isStartUserAction) { // 添加第二个锚点到历史栈 history.pushState({ anchor: settings.startLogicAnchor }, '', methods.setAnchor(settings.startLogicAnchor)); isStartUserAction = true; } }).on('scroll', debounce(function () { if (!isStartUserAction) { history.pushState({ anchor: settings.startLogicAnchor }, '', methods.setAnchor(settings.startLogicAnchor)); isStartUserAction = true; } }, 200)); // 200ms防抖延迟,可根据需求调整 window.onpopstate = function(event) { // 校验返回状态:从第二个锚点回到第一个锚点,且弹窗未显示 if (isStartUserAction && !isShowedModal && event.state?.anchor === settings.initAnchor) { methods.show(); isShowedModal = true; // 维持当前锚点状态,避免再次返回时重复触发 history.pushState({ anchor: settings.initAnchor }, '', methods.setAnchor(settings.initAnchor)); } };
关键修改说明
- 用
history.pushState替代window.location.href:精准控制历史栈条目,确保每一步锚点切换都被记录,返回时能正确回溯到初始锚点状态。 - 滚动事件防抖:避免滚动过程中多次触发锚点切换,防止历史栈混乱。
popstate事件增加状态校验:通过event.state判断是否是从第二个锚点返回第一个锚点,同时标记弹窗已显示,避免重复触发。
内容的提问来源于stack exchange,提问作者Kirill Zaytsev
相关产品推荐
相关产品推荐

