fix(feed): 改用 articlesWithPrompts computed + TransitionGroup 正确联动

问题: 之前用 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 本身)
This commit is contained in:
xiaji
2026-06-15 21:35:35 +08:00
parent 4f98fb8779
commit de4a88ce8b

View File

@@ -39,6 +39,15 @@ const categoryPromptsByArticle = ref<Map<number, CategoryPromptItem[]>>(new Map(
const pendingCategory = ref<string | null>(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 () => {
</NCard>
<!--
该文章对应的分类提示条(per-article 挂载,卡片**下方**):
- 独立的 v-for 循环,key 用 a.id 跟 NCard 共享,这样 hide_read 模式下
items.splice 移除文章时,提示条会跟 NCard 同步触发 leave 动画
- 用 articlesWithPrompts(过滤后只有有提示条的 article)做 v-for
- key 用 a.id 跟 NCard 共享(但 NCard 已经在自己的 v-for 里,key 不冲突,
因为这是独立的 v-for 节点),hide_read 模式下 items.splice 移除文章时,
对应的提示条 wrapper 会从 articlesWithPrompts 移除 → leave 动画
- 内部 NAlert v-for 用 ${a.id}-${category} 作为 key,确保多个 category 时各自独立
- 用 v-show 而非 v-if:v-for 始终渲染 wrapper,内部 NAlert 按需显示
-->
<div
v-for="a in items"
v-show="!!categoryPromptsByArticle.get(a.id)?.length"
v-for="a in articlesWithPrompts"
:key="`prompt-wrapper-${a.id}`"
class="feed-category-prompt-wrapper"
>