From b6a9f598b53648fad69883eea51b5f61d3ffd166 Mon Sep 17 00:00:00 2001 From: kaireewu Date: Sun, 1 Nov 2026 02:02:26 +0800 Subject: [PATCH] fix(web): avoid skeleton flicker and cache overview while filtering --- reaction_board/web/static/router.js | 7 +++++-- reaction_board/web/static/views/rankings.js | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/reaction_board/web/static/router.js b/reaction_board/web/static/router.js index 0bcc757..d58ad85 100644 --- a/reaction_board/web/static/router.js +++ b/reaction_board/web/static/router.js @@ -136,8 +136,11 @@ async function render(options = {}) { if (scrollTop && !preserveScroll) { window.scrollTo({ top: 0, behavior: "auto" }); } - routeElement.innerHTML = `
-
`; + if (!preserveScroll) { + // 保留滚动位置的原地更新不要插入骨架屏,否则列表会短暂消失、滚动条闪烁。 + routeElement.innerHTML = `
+
`; + } try { await matched.route.view(routeElement, { params: matched.match.slice(1), diff --git a/reaction_board/web/static/views/rankings.js b/reaction_board/web/static/views/rankings.js index bbd01e5..68f1d0b 100644 --- a/reaction_board/web/static/views/rankings.js +++ b/reaction_board/web/static/views/rankings.js @@ -16,6 +16,21 @@ const UP_SORTS = [ ["count", "视频数"], ["views", "总播放"], ]; const METRIC_PRIMARY = new Set(["view", "like", "coin", "favorite", "share", "reply", "danmaku"]); +const OVERVIEW_TTL = 60_000; +let overviewCache = { at: 0, promise: null }; + +async function getOverview() { + const now = Date.now(); + if (!overviewCache.promise || now - overviewCache.at > OVERVIEW_TTL) { + overviewCache = { at: now, promise: api("/api/overview") }; + } + try { + return await overviewCache.promise; + } catch (error) { + overviewCache = { at: 0, promise: null }; + throw error; + } +} function controls({ scope, sort, within, growthDays, q, folder, minVideos, folders }) { const sorts = scope === "up" ? UP_SORTS : VIDEO_SORTS; @@ -87,7 +102,7 @@ export async function renderRankings(root, { query }) { const minVideos = query.get("min_videos") || "1"; const page = Math.max(1, Number(query.get("page") || 1)); - const overview = await api("/api/overview"); + const overview = await getOverview(); const folders = overview.folders || []; const params = {