🐛 fix(vscode): 代码阅读预览跳到定义后页面还在长高(注释里的 mermaid 画成图、中文名到了)不再把视口带跑:页面滚动统一交给滚动所有者,跟住跳到的目标、用户自己滚了改钉视口顶部那块,关掉浏览器自带的滚动锚定

This commit is contained in:
cruldra committed 2026-10-14 06:11:25 +11:00
1 parent 2fa6319dd4
commit 3c5f5f5f35
24 files changed
+1016 -149

No files matched your search

@@ -8,6 +8,7 @@ import { documentNameAt, PEEK_ATTRIBUTE } from './definitionPeek'
import { clickAction, KeyScroll, OccurrenceHighlight, occurrenceJumpKey, OccurrenceNavigation } from './occurrences'
import { nameOffset, NO_PLACEMENT } from './placement'
import { occurrencePlan } from './reveal'
import { scrollOwner } from './scrollOwner'
import { useStore } from './store'
import { showInViewport } from './useReveal'
import { onMessage, postMessage } from './vscode'
@@ -64,19 +65,6 @@ function isMac(): boolean {
return /Mac|iPhone|iPad/.test(navigator.platform)
}
/**
* 立刻滚到这里,顺带打断浏览器正在播(或刚排上、还没开始播)的滚动动画。滚到原地浏览器当没滚、不打断动画,
* 所以先挪一个像素再回来:同一段脚本里连着滚两下,中间不画,画面上看不出。
* 这两处位置先交给 own:滚动事件可能晚于这次调用才到,不能被当成浏览器把页面滚走。
*/
function scrollBack({ x, y }: ScrollPosition, own: (position: ScrollPosition) => void): void {
const nudged = { x, y: y > 0 ? y - 1 : y + 1 }
own(nudged)
own({ x, y })
window.scrollTo({ left: x, top: nudged.y, behavior: 'instant' })
window.scrollTo({ left: x, top: y, behavior: 'instant' })
}
/**
* 单击名字高亮它在文档里的各处出现,点空白处、Esc、换文档版本或翻译清掉;高亮着的名字记进 marks(页面文字的标记),返回它和筛选栏上「上一处 / 下一处」用的跳转。
* 高亮着时扩展端的「跳到下一处 / 上一处高亮」命令发来 moveOccurrence,筛选栏上的按钮走同一条跳转:当前那一处换成下一处页面上找得到的出现,
@@ -109,9 +97,9 @@ export function useOccurrences(version: number | undefined, translatorId: string
useLayoutEffect(() => {
if (moves === 0)
return
const el = document.querySelector<HTMLElement>('[data-current]')
if (el)
showInViewport(el, position => keyScroll.own(position))
const current = (): HTMLElement | null => document.querySelector<HTMLElement>('[data-current]')
if (current())
showInViewport(current)
keyScroll.hold(scrollPosition())
}, [moves, keyScroll])
@@ -121,7 +109,7 @@ export function useOccurrences(version: number | undefined, translatorId: string
// 触发命令的那个键浏览器可能已经照自己的意思滚了(⌘↓ 滚到底),先回到按键那一刻
const before = keyScroll.take(performance.now())
if (before)
scrollBack(before, position => keyScroll.own(position))
scrollOwner.pullBack(before)
}
else {
// 筛选栏按钮不是按键,别把这次滚动当成 ⌘↓ 拉回按键时的位置
@@ -150,10 +138,10 @@ export function useOccurrences(version: number | undefined, translatorId: string
keyScroll.press(scrollPosition(), event.timeStamp)
}
const onPointer = (): void => keyScroll.forget()
const onScroll = (event: Event): void => {
const back = keyScroll.scrolled(event.timeStamp, scrollPosition)
const onScroll = (ours: boolean, event: Event): void => {
const back = keyScroll.scrolled(event.timeStamp, scrollPosition, ours)
if (back)
scrollBack(back, position => keyScroll.own(position))
scrollOwner.pullBack(back)
}
const onKey = (event: KeyboardEvent): void => {
// 输入框、下拉列表自己用掉的 Esc 不算
@@ -175,7 +163,7 @@ export function useOccurrences(version: number | undefined, translatorId: string
window.addEventListener('keydown', onKeyDown, true)
window.addEventListener('pointerdown', onPointer, true)
window.addEventListener('wheel', onPointer, { capture: true, passive: true })
window.addEventListener('scroll', onScroll, { passive: true })
const offScroll = scrollOwner.onScroll(onScroll)
window.addEventListener('keydown', onKey)
window.addEventListener('focus', onFocus)
window.addEventListener('blur', onBlur)
@@ -187,7 +175,7 @@ export function useOccurrences(version: number | undefined, translatorId: string
window.removeEventListener('keydown', onKeyDown, true)
window.removeEventListener('pointerdown', onPointer, true)
window.removeEventListener('wheel', onPointer, { capture: true })
window.removeEventListener('scroll', onScroll)
offScroll()
window.removeEventListener('keydown', onKey)
window.removeEventListener('focus', onFocus)
window.removeEventListener('blur', onBlur)