fix(feed): hide_read 模式不再 splice 文章,改用视觉降级
This commit is contained in:
@@ -210,54 +210,11 @@ async function toggleRead(a: ArticleListItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hide_read 模式:卡片从列表里消失(用户预期行为)
|
// hide_read 模式:卡片**保留在列表里**(视觉降级为 opacity 0.7)
|
||||||
// 但如果该文章有提示条,推迟 splice 到提示条消失后再做
|
// 不再 splice 移除文章 — 否则会触发 NCard 的 leave 动画,
|
||||||
if (!wasRead && hideRead.value) {
|
// 进而影响 wrapper 显示,导致分类提示条看不见
|
||||||
const hasPrompt = (categoryPromptsByArticle.value.get(a.id)?.length ?? 0) > 0
|
// 用户主动刷新 / 切页时 hideRead=true 的过滤会自然把已读过滤掉
|
||||||
const delay = hasPrompt ? 8200 : 360 // 有提示:让提示条走完 8s;无提示:照旧
|
// (hide_read 模式的"splice"逻辑废弃,保留 is_read 状态以驱动 article-card-read 样式)
|
||||||
if (hasPrompt) {
|
|
||||||
// 监听 8s 计时器到期 / dismiss / confirm
|
|
||||||
// 用 watchEffect 监听 Map 变化,提示条消失后再 splice
|
|
||||||
const stopWatch = watch(
|
|
||||||
() => categoryPromptsByArticle.value.get(a.id),
|
|
||||||
(newVal) => {
|
|
||||||
if (!newVal || newVal.length === 0) {
|
|
||||||
stopWatch()
|
|
||||||
const idx = items.value.findIndex((x) => x.id === a.id)
|
|
||||||
if (idx >= 0) {
|
|
||||||
pendingRemoval.value.add(a.id)
|
|
||||||
items.value.splice(idx, 1)
|
|
||||||
pendingRemoval.value.delete(a.id)
|
|
||||||
if (total.value > 0) total.value -= 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: false },
|
|
||||||
)
|
|
||||||
// 兜底:8.2s 强制结束(防止 watch 漏掉)
|
|
||||||
setTimeout(() => {
|
|
||||||
stopWatch()
|
|
||||||
const idx = items.value.findIndex((x) => x.id === a.id)
|
|
||||||
if (idx >= 0) {
|
|
||||||
pendingRemoval.value.add(a.id)
|
|
||||||
items.value.splice(idx, 1)
|
|
||||||
pendingRemoval.value.delete(a.id)
|
|
||||||
if (total.value > 0) total.value -= 1
|
|
||||||
}
|
|
||||||
}, delay)
|
|
||||||
} else {
|
|
||||||
const idx = items.value.findIndex((x) => x.id === a.id)
|
|
||||||
if (idx >= 0) {
|
|
||||||
pendingRemoval.value.add(a.id)
|
|
||||||
setTimeout(() => {
|
|
||||||
const i = items.value.findIndex((x) => x.id === a.id)
|
|
||||||
if (i >= 0) items.value.splice(i, 1)
|
|
||||||
pendingRemoval.value.delete(a.id)
|
|
||||||
if (total.value > 0) total.value -= 1
|
|
||||||
}, delay)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
// 失败回滚
|
// 失败回滚
|
||||||
a.is_read = wasRead
|
a.is_read = wasRead
|
||||||
@@ -319,21 +276,9 @@ async function confirmMarkCategory(articleId: number, category: string) {
|
|||||||
for (const item of items.value) {
|
for (const item of items.value) {
|
||||||
if (ids.has(item.id)) item.is_read = true
|
if (ids.has(item.id)) item.is_read = true
|
||||||
}
|
}
|
||||||
// 走 hide_read 模式下的滑出(累计 delay,逐个错开,避免 30 个 setTimeout 同时触发视觉抖)
|
// 走 hide_read 模式下的滑出 — 已废弃,改成已读卡片视觉降级
|
||||||
let i = 0
|
// 原因:批量 splice 触发的 NCard leave 动画会带歪提示条 wrapper
|
||||||
for (const id of resp.article_ids) {
|
// 用户主动刷新 / 切页时,hideRead=true 的过滤会自然把已读过滤掉
|
||||||
const idx = items.value.findIndex((x) => x.id === id)
|
|
||||||
if (idx < 0) continue
|
|
||||||
pendingRemoval.value.add(id)
|
|
||||||
const delay = 360 + i * 20
|
|
||||||
i++
|
|
||||||
setTimeout(() => {
|
|
||||||
const k = items.value.findIndex((x) => x.id === id)
|
|
||||||
if (k >= 0) items.value.splice(k, 1)
|
|
||||||
pendingRemoval.value.delete(id)
|
|
||||||
if (total.value > 0) total.value -= 1
|
|
||||||
}, delay)
|
|
||||||
}
|
|
||||||
// 关闭该 article 的整组提示(不只关 category — 既然"全部已读"了,这一片都不需要了)
|
// 关闭该 article 的整组提示(不只关 category — 既然"全部已读"了,这一片都不需要了)
|
||||||
clearPromptsForArticle(articleId)
|
clearPromptsForArticle(articleId)
|
||||||
message.success(`已将 ${resp.marked} 条「${category}」标记为已读`)
|
message.success(`已将 ${resp.marked} 条「${category}」标记为已读`)
|
||||||
@@ -746,9 +691,9 @@ onMounted(async () => {
|
|||||||
<!--
|
<!--
|
||||||
该文章对应的分类提示条(per-article 挂载,卡片**下方**):
|
该文章对应的分类提示条(per-article 挂载,卡片**下方**):
|
||||||
- 用 articlesWithPrompts(过滤后只有有提示条的 article)做 v-for
|
- 用 articlesWithPrompts(过滤后只有有提示条的 article)做 v-for
|
||||||
- key 用 a.id 跟 NCard 共享(但 NCard 已经在自己的 v-for 里,key 不冲突,
|
- 跟 NCard 在同一个 TransitionGroup,但 hide_read 模式不再 splice 移除文章,
|
||||||
因为这是独立的 v-for 节点),hide_read 模式下 items.splice 移除文章时,
|
所以 NCard 不会触发 leave 动画,wrapper 不会被卷走
|
||||||
对应的提示条 wrapper 会从 articlesWithPrompts 移除 → leave 动画
|
- 8s 后 Map 删掉 → wrapper 走自己的 leave 动画(只影响 wrapper,不影响 NCard)
|
||||||
- 内部 NAlert v-for 用 ${a.id}-${category} 作为 key,确保多个 category 时各自独立
|
- 内部 NAlert v-for 用 ${a.id}-${category} 作为 key,确保多个 category 时各自独立
|
||||||
-->
|
-->
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user