fix(UI): 在根布局建立滚轮事件边界,避免 ScriptCat 内部滚动触发浏览器 swipe 跳页#1431
Open
cyfung1031 wants to merge 5 commits intomainfrom
Open
fix(UI): 在根布局建立滚轮事件边界,避免 ScriptCat 内部滚动触发浏览器 swipe 跳页#1431cyfung1031 wants to merge 5 commits intomainfrom
cyfung1031 wants to merge 5 commits intomainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
该 PR 旨在通过在 #root 层面隔离 wheel 事件与调整根节点滚动相关 CSS,避免页面互动时滚轮事件“穿透”到 body/html 从而触发浏览器的 swipe 跳页行为;同时对 Monaco 编辑器区域做特殊处理以保持编辑器滚动体验稳定。
Changes:
- 新增
ScrollBoundary组件:在指定根节点上注册wheel监听,对 Monaco 区域preventDefault(),其他区域阻断事件传播。 - 在
MainLayout根部引入并包裹ScrollBoundary,将边界逻辑统一作用于页面根容器。 - 调整全局样式:为
#root增加overscroll-behavior/contain/overflow,并新增全局scrollbar-color继承规则。
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/pages/components/layout/ScrollBoundary.tsx | 新增滚轮事件边界组件并在根节点绑定 wheel 监听以隔离滚动手势影响范围 |
| src/pages/components/layout/MainLayout.tsx | 在布局根部包裹 ScrollBoundary,将滚轮隔离策略应用到整个页面内容树 |
| src/index.css | 通过 #root 的 overscroll/overflow/contain 等样式尝试抑制 swipe 跳页,并调整滚动条颜色继承策略 |
Comment on lines
+52
to
+56
| export default function ScrollBoundary({ children, parentNodeSelector }: ScrollBoundaryProps) { | ||
| // Attach once per render; the handler is idempotent due to the | ||
| // remove-then-add pattern in attachScrollBoundaryHandler. | ||
| attachScrollBoundaryHandler(document.querySelector(parentNodeSelector)); | ||
| return <>{children}</>; |
Collaborator
Author
There was a problem hiding this comment.
不用移除。都是加载在 DOM Node 本身。 DOM 被移除就会清掉 (虽然 #root 不会有这个可能)
| * scrolling within non-editor children.) | ||
| */ | ||
| const handleScrollBoundaryWheel = (evt: Event) => { | ||
| if ((evt.target as Element).closest(".monaco-editor")) { |
Collaborator
Author
There was a problem hiding this comment.
只会是 Element (#root)
|
|
||
| #root { | ||
| overscroll-behavior: none; | ||
| contain: content; |
Collaborator
Author
There was a problem hiding this comment.
不需要。#root 已是最外层。不影响
Comment on lines
+5
to
+8
| * { | ||
| scrollbar-color: inherit; | ||
| } | ||
|
|
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
上次的 #1413 修完后还是不满意效果。好像不稳定
这个 ScrollBoundary 是针对整个
#root所有 wheel 跑到这个
#root外层就会截下来, 不让 body/html 触发 swipe 跳页Checklist / 检查清单
背景
#1413 已针对脚本列表横向滚动、Monaco 编辑器横向滚动导致浏览器触发「上一页 / 下一页」的问题做过局部修正,但实际使用中仍存在不稳定情况。
在 ScriptCat 的 options 页面里,脚本列表、脚本编辑器、弹窗、下拉菜单等组件都运行在同一个 React 根节点下。部分区域,尤其是 Monaco 编辑器和可横向滚动的内容区域,在触控板或鼠标滚轮产生横向滚动时,
wheel事件仍可能继续向body/html传播,进而触发浏览器或宿主页面的 swipe back/forward 行为,表现为用户只是在页面内滚动,却意外跳转到上一页。因此这次不再只依赖局部
overscroll-behavior,而是在 ScriptCat 应用根节点建立统一的滚轮事件边界。本次变更
1. 新增
ScrollBoundary组件新增
src/pages/components/layout/ScrollBoundary.tsx,用于在指定父节点上注册wheel事件监听器。当前接入点为
#root,也就是 ScriptCat React 应用的根容器。处理策略:
preventDefault(),避免事件继续触发浏览器 / 页面级横向滑动行为。stopImmediatePropagation()和stopPropagation(),阻止事件继续冒泡到根节点外部。preventDefault(),保留脚本列表、弹窗、下拉菜单等区域自身的原生滚动能力。passive: false,确保 Monaco 场景下的preventDefault()可以生效。2. 在
MainLayout中包裹全局布局将 ScriptCat options 页面内的主要 UI 都纳入同一个滚动边界中,包括顶部工具栏、脚本导入弹窗、脚本列表、脚本编辑器和子路由页面。
这样可以避免每个页面或组件单独处理滚轮穿透问题,后续新增可滚动区域时也能复用这层根节点保护。
3. 调整全局滚动样式
src/index.css中对#root增加:作用是将 ScriptCat 应用根容器明确作为滚动边界,减少滚动链继续传递到
body/html的机会。同时将滚动条颜色改为通过
* { scrollbar-color: inherit; }继承,继续保持 light/dark theme 下滚动条样式一致。为什么这样改
之前 #1413 的修复更偏向局部:在脚本列表和编辑器相关容器上增加
tw-overscroll-none。这种方式可以覆盖已知区域,但对复杂嵌套组件、Monaco 内部滚动实现、弹层组件以及后续新增滚动区域并不够稳。这次改为在
#root上建立统一的ScrollBoundary,把「ScriptCat 内部滚动」和「浏览器页面级 swipe 行为」隔离开:影响范围
#root内部的wheel事件处理。测试
已验证: