From de4a88ce8bac4408b466d6d2fac016b24e36a5e6 Mon Sep 17 00:00:00 2001 From: xiaji Date: Mon, 15 Jun 2026 21:35:35 +0800 Subject: [PATCH] =?UTF-8?q?fix(feed):=20=E6=94=B9=E7=94=A8=20articlesWithP?= =?UTF-8?q?rompts=20computed=20+=20TransitionGroup=20=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E8=81=94=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: 之前用 v-for items + v-show,虽然类型对,但 v-show 元素始终在 DOM, TransitionGroup 的 leave 动画处理的是 v-for key 移除,而 v-show 元素 不在 v-for 移除路径上 → 提示条几乎瞬间消失(用户看不见) 修法: 抽 articlesWithPrompts = items.filter(hasPrompt) computed - 只有真有提示条的 article 才进 wrapper v-for - hide_read 模式下,items.splice 移除 a 时 articlesWithPrompts 也跟着变 - TransitionGroup 对 wrapper 节点触发 leave 动画,跟 NCard 同步 - 没有 v-for+v-if 同元素的 TS warning - 不会有孤儿 wrapper(过滤基于 items 本身) --- frontend/src/views/Feed.vue | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/frontend/src/views/Feed.vue b/frontend/src/views/Feed.vue index 014ce64..b8de657 100644 --- a/frontend/src/views/Feed.vue +++ b/frontend/src/views/Feed.vue @@ -39,6 +39,15 @@ const categoryPromptsByArticle = ref>(new Map( const pendingCategory = ref(null) // 正在请求"全部已读"的分类(category 名) let categoryPromptTimer: number | null = null +// 只渲染"还在 items 里"且"有提示条"的 article 列表(给 TransitionGroup 用作 v-for) +// computed 保证响应式 +// - items 没这条 → 不渲染(孤儿) +// - items 有 + Map 也有 → 渲染 +// - items 有 + Map 没 → 不渲染(用户已 dismiss/确认/超时) +const articlesWithPrompts = computed(() => + items.value.filter((a) => (categoryPromptsByArticle.value.get(a.id)?.length ?? 0) > 0) +) + // 移除某篇文章的所有提示条(8 秒超时 / 确认后 / 过滤变化) function clearPromptsForArticle(articleId: number) { if (categoryPromptsByArticle.value.has(articleId)) { @@ -693,14 +702,14 @@ onMounted(async () => {