如何阻止嵌入的JavaScript触发网页自动滚动?
阻止嵌入日历JavaScript触发页面自动滚动的可落地方案
所有方案适配Squarespace站点的代码注入规则,无需修改第三方日历的源代码即可生效:
核心拦截思路
第三方嵌入脚本触发的自动滚动,本质都是调用浏览器内置的滚动API完成位置跳转,我们不需要修改第三方脚本本身,只需要在脚本执行前对这些滚动API做权限校验,只放行真实用户手势触发的滚动,拦截脚本内部的自动调用即可。
具体实现步骤
- 全局拦截滚动API的自动调用
将以下代码添加到Squarespace的全站代码注入区域(网站后台 > 设置 > 高级 > 代码注入 > 页头),确保第三方日历脚本加载前就完成拦截逻辑初始化:
这段逻辑不会影响用户正常的手动滑动、点击导航链接跳转等常规滚动体验,只会拦截没有真实用户输入触发的、由脚本内部逻辑触发的自动滚动。const originalScrollTo = window.scrollTo; const originalScrollIntoView = Element.prototype.scrollIntoView; // 校验滚动触发源,仅放行真实用户交互的滚动操作 window.scrollTo = function() { if (window.event && window.event.isTrusted) { originalScrollTo.apply(this, arguments); } } Element.prototype.scrollIntoView = function() { if (window.event && window.event.isTrusted) { originalScrollIntoView.apply(this, arguments); } } - 补全直接修改滚动位置的拦截逻辑
部分脚本不会通过标准API触发滚动,而是直接修改页面元素的scrollTop属性调整位置,需要在之前的拦截代码后补充以下逻辑覆盖这类场景:const rootEl = document.documentElement; let safeScrollTop = rootEl.scrollTop; Object.defineProperty(rootEl, 'scrollTop', { get: () => safeScrollTop, set: (newVal) => { if (window.event && window.event.isTrusted) { safeScrollTop = newVal; rootEl.scrollTop = safeScrollTop; } } }) - 懒加载脚本降低bug触发影响
如果拦截后仍存在轻微的滚动跳动,可以调整原嵌入日历代码的加载逻辑:删掉原代码里的<script async src="https://kati.loxi.io/embed/client.js"></script>部分,替换为以下懒加载代码,放在日历组件p标签的后面:
这种方式下,用户打开页面时日历脚本不会自动加载,自然不会触发初始化阶段的自动滚动;只有当用户即将滚动到日历位置时,脚本才会开始加载,即使脚本内部保留自动滚动逻辑,也不会出现从页面顶部直接跳转到日历位置的割裂感。const calendarContainer = document.querySelector('p.loxi'); const calendarScript = document.createElement('script'); calendarScript.src = 'https://kati.loxi.io/embed/client.js'; calendarScript.async = true; // 当用户滚动到距离日历组件200px范围内时,再加载日历脚本 const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { document.body.appendChild(calendarScript); observer.disconnect(); } }, { rootMargin: '200px 0px' }); observer.observe(calendarContainer); - 临时兜底滚动锁
若以上方案仍无法完全挡住滚动跳动,可以在页面初始化阶段加一段2秒的临时滚动锁,等日历脚本的初始化bug逻辑全部执行完成后再解锁滚动:const initialPosition = window.scrollY; const unlockTime = Date.now() + 2000; const lockTimer = setInterval(() => { if (Date.now() > unlockTime) { clearInterval(lockTimer); return; } // 锁定期内强制保持页面在初始打开位置 window.scrollTo(0, initialPosition); }, 10);
内容的提问来源于stack exchange,提问作者Samuel Stevenson
相关产品推荐
相关产品推荐

