iOS Safari中DOMContentLoaded失效,页面重载无法恢复滚动位置
iOS Safari表单提交后无法恢复滚动位置的问题修复
问题背景
页面重载(如表单提交后)需要保存并恢复当前滚动位置,现有代码在Chrome、Firefox及Android端浏览器正常生效,但在iOS Safari中无效。已针对DOMContentLoaded事件提前触发的问题做了修复,部署后问题仍存在。
原代码如下:
<script> function afterDOMLoaded() { var scrollpos = sessionStorage.getItem('scrollpos'); if (scrollpos) { window.scrollTo(0, scrollpos); sessionStorage.removeItem('scrollpos'); } window.addEventListener("beforeunload", function (e) { sessionStorage.setItem('scrollpos', window.scrollY); }); } if(document.readyState === 'loading') { document.addEventListener('DOMContentLoaded',afterDOMLoaded); } else { afterDOMLoaded(); } </script>
失效原因
beforeunload触发时机异常:iOS Safari在表单提交时,beforeunload事件触发时页面已开始卸载,window.scrollY可能已被重置为0,导致保存的滚动位置错误。- sessionStorage读取延迟:DOMContentLoaded触发时,Safari可能还未完成sessionStorage的读取操作,导致无法获取到之前保存的滚动位置。
- 默认滚动恢复机制冲突:iOS Safari自带页面重载后自动恢复滚动位置的功能,会覆盖自定义的滚动恢复逻辑。
修复方案
1. 替换beforeunload为表单submit事件监听
针对表单提交场景,直接在表单提交时保存滚动位置,避免beforeunload的时机问题:
function saveScrollPos() { sessionStorage.setItem('scrollpos', window.scrollY); } // DOM加载完成后给所有表单绑定提交事件 document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('form').forEach(form => { form.addEventListener('submit', saveScrollPos); }); });
2. 延迟执行滚动恢复逻辑
给scrollTo添加微小延迟,确保sessionStorage读取完成,同时避开Safari的默认滚动时机:
function afterDOMLoaded() { var scrollpos = sessionStorage.getItem('scrollpos'); if (scrollpos) { setTimeout(() => { window.scrollTo(0, parseInt(scrollpos)); sessionStorage.removeItem('scrollpos'); }, 100); } }
3. 禁用浏览器默认滚动恢复
关闭Safari自带的滚动恢复功能,避免与自定义逻辑冲突:
if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; }
完整修复代码
<script> // 禁用浏览器默认滚动恢复 if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; } function saveScrollPos() { sessionStorage.setItem('scrollpos', window.scrollY); } function afterDOMLoaded() { var scrollpos = sessionStorage.getItem('scrollpos'); if (scrollpos) { setTimeout(() => { window.scrollTo(0, parseInt(scrollpos)); sessionStorage.removeItem('scrollpos'); }, 100); } // 绑定所有表单的提交事件 document.querySelectorAll('form').forEach(form => { form.addEventListener('submit', saveScrollPos); }); } if(document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', afterDOMLoaded); } else { afterDOMLoaded(); } </script>
内容的提问来源于stack exchange,提问作者kingx26
相关产品推荐
相关产品推荐

