From af1c089506d2231ab7eb454336d4b8dfec02e69d Mon Sep 17 00:00:00 2001 From: cruldra Date: Tue, 13 Oct 2026 15:21:50 +1100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(vscode):=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=98=85=E8=AF=BB=E9=A2=84=E8=A7=88=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E9=97=AA=E7=83=81=E6=8C=89=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E6=97=B6=E9=95=BF=E5=88=B0=E7=82=B9=E6=91=98=E6=8E=89=EF=BC=8C?= =?UTF-8?q?=E6=BB=9A=E5=88=B0=E7=94=BB=E9=9D=A2=E5=A4=96=E8=A2=AB=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=E6=8E=92=E7=89=88=E7=9A=84=E5=9D=97=E9=87=8C=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E5=81=9C=E7=9D=80=E7=AD=89=E4=B8=8D=E5=88=B0=E7=BB=93?= =?UTF-8?q?=E6=9D=9F=E4=BA=8B=E4=BB=B6=EF=BC=8C=E4=B8=8A=E4=B8=80=E5=A4=84?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E4=B8=80=E7=9B=B4=E9=97=AA=E7=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webview-ui/src/codeReader/pageLayout.ts | 6 ++-- vscode/webview-ui/src/codeReader/useReveal.ts | 30 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/vscode/webview-ui/src/codeReader/pageLayout.ts b/vscode/webview-ui/src/codeReader/pageLayout.ts index 66da1e1..972a783 100644 --- a/vscode/webview-ui/src/codeReader/pageLayout.ts +++ b/vscode/webview-ui/src/codeReader/pageLayout.ts @@ -85,6 +85,9 @@ export class PageLayout { private items: ItemBox[] | undefined private cards = new Map() private barHeight: number | undefined + /** 要滚过去、先照常排版着的顶层块(见 settle),和放回去的那一帧 */ + private settling: HTMLElement[] = [] + private release = 0 /** 量 root(块树所在的页面内容)里的卡片,筛选栏是 bar;返回停止观察的函数 */ attach(root: HTMLElement, bar: HTMLElement | null): () => void { @@ -188,9 +191,6 @@ export class PageLayout { return this.itemBoxes() } - private settling: HTMLElement[] = [] - private release = 0 - private settleAround(index: number): void { const items = this.itemBoxes() const view = window.innerHeight diff --git a/vscode/webview-ui/src/codeReader/useReveal.ts b/vscode/webview-ui/src/codeReader/useReveal.ts index 1c07c8b..2e6d107 100644 --- a/vscode/webview-ui/src/codeReader/useReveal.ts +++ b/vscode/webview-ui/src/codeReader/useReveal.ts @@ -6,22 +6,24 @@ import { pageLayout } from './pageLayout' import { revealPlan, scrollTopToShow, uncoveredPlan } from './reveal' import { stickyHeight } from './useStickyScroll' -/** 让一块或属性表里的一行闪几下(codeReader.css 的 [data-flash]);正在闪的同一处再跳一次时从头闪。 */ +/** 正在闪的元素和到点摘掉 data-flash 的计时器 */ +const flashing = new WeakMap() + +/** + * 让一块或属性表里的一行闪几下(codeReader.css 的 [data-flash]);正在闪的同一处再跳一次时从头闪。 + * 闪完(按 CSS 动画的时长)摘掉 data-flash:用计时器而不是等 animationend,滚到画面外被跳过排版的块(content-visibility)里动画停着,等不到它。 + */ export function flash(el: HTMLElement): void { - const running = el.getAnimations().filter(animation => animation instanceof CSSAnimation) - if (running.length > 0) { - for (const animation of running) - animation.currentTime = 0 - return - } - const onEnd = (event: AnimationEvent): void => { - if (event.target !== el) - return - el.removeAttribute('data-flash') - el.removeEventListener('animationend', onEnd) - } - el.addEventListener('animationend', onEnd) + window.clearTimeout(flashing.get(el)) el.setAttribute('data-flash', '') + const animations = el.getAnimations().filter(animation => animation instanceof CSSAnimation) + for (const animation of animations) + animation.currentTime = 0 + const end = Math.max(0, ...animations.map(animation => Number(animation.effect?.getComputedTiming().endTime ?? 0))) + flashing.set(el, window.setTimeout(() => { + el.removeAttribute('data-flash') + flashing.delete(el) + }, end)) } /** 把 el 滚进钉住的筛选栏和卡片下面的视口,量之前先把它那一带排版好(pageLayout.settle)。已经整个看得见就不滚。beforeScroll 在真正滚动前拿到将要落到的位置。 */