🐛 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

@@ -3,6 +3,7 @@ import type { StickyScrollSettings } from './types'
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
import { nextStop } from './diffView'
import { pageLayout } from './pageLayout'
import { scrollOwner } from './scrollOwner'
import { flash } from './useReveal'
import { stickyInset } from './useStickyScroll'
@@ -12,15 +13,16 @@ const MARGIN = 8
/**
* 「上一处 / 下一处」和点总览条的刻度:跳到一处改动。它在折叠着的块里时先展开那几层(expand),渲染好了再把它滚到筛选栏下面
* (钉着外层卡片时在钉着的几行下面,sticky 是 VS Code 的 Sticky Scroll 设置)、闪几下。
* 接着走从哪算:跳完之后页面没滚过就从刚跳到的那处接着走,用户自己滚过了就按视口顶上那块的行找(见 nextStop)。
* 跳过去以后由 [scrollOwner] 跟住那张卡片。接着走从哪算:跳完之后用户没滚过、也没跳到别处就从刚跳到的那处接着走,
* 否则按视口顶上那块的行找(见 [nextStop]);页面长高时滚动所有者自己滚回去的不算用户滚过。
*/
export function useChangeNav(stops: readonly ChangeStop[], collapsed: ReadonlySet<string>, expand: (ids: string[]) => void, sticky: StickyScrollSettings | undefined): {
move: (step: 1 | -1) => void
goTo: (stop: ChangeStop) => void
} {
const [target, setTarget] = useState<ChangeStop | null>(null)
/** 最近一次跳到的那处,和跳完时页面滚到哪 */
const jumped = useRef<{ id: string, scrollY: number } | null>(null)
/** 最近一次跳到的那处,和跳完时页面换过几次地方(见 [ScrollOwner.turn](vscode/webview-ui/src/codeReader/scrollOwner.ts#ScrollOwner.turn)) */
const jumped = useRef<{ id: string, turn: number } | null>(null)
useLayoutEffect(() => {
if (!target)
@@ -30,20 +32,22 @@ export function useChangeNav(stops: readonly ChangeStop[], collapsed: ReadonlySe
expand(hidden)
return
}
const card = document.querySelector<HTMLElement>(`.cr-block[data-id="${target.id}"]`)
const locate = (): HTMLElement | null => document.querySelector<HTMLElement>(`.cr-block[data-id="${target.id}"]`)
const card = locate()
if (card) {
pageLayout.settle(card)
window.scrollTo(0, card.getBoundingClientRect().top + window.scrollY - pageLayout.pinnedHeight() - stickyInset(card, sticky) - MARGIN)
const inset = pageLayout.pinnedHeight() + stickyInset(card, sticky) + MARGIN
scrollOwner.reveal(locate, box => box.top - inset)
flash(card)
}
jumped.current = { id: target.id, scrollY: window.scrollY }
jumped.current = { id: target.id, turn: scrollOwner.turn }
setTarget(null)
}, [target, collapsed, expand, sticky])
const move = useCallback((step: 1 | -1) => {
if (stops.length === 0)
return
const from = jumped.current && Math.abs(window.scrollY - jumped.current.scrollY) < 2 ? jumped.current.id : undefined
const from = jumped.current?.turn === scrollOwner.turn ? jumped.current.id : undefined
const index = from === undefined ? -1 : stops.findIndex(stop => stop.id === from)
const at = index >= 0 ? { index } : { line: pageLayout.anchorAt(window.scrollY + pageLayout.pinnedHeight())?.line }
setTarget(stops[nextStop(stops, at, step)])