Skip to content
返回设计中心

收藏与书签模式

让用户稍后保存项,含乐观 UI、持久化、空状态。

UX 模式入门

为什么

用户找到想重访的项但不想再搜。收藏给他们持久 '已存' 列表 — 高参与特性,便宜建且离线工作。

Nielsen Norman Group 研究显示用户在离开前平均停留 10-15 秒。清晰的视觉层次和渐进式披露将任务完成率提高 40-60%。

何时使用

任何有用户可能重访可浏览内容的应用:产品、文章、房产、工作、搜索结果。跳过一次性内容(收据、确认)。

如何做

1. 切换 UI — 星/心图标、乐观翻转、填充 vs 轮廓状态 2. 存储 — 用户作用域项 ID 列表;持久到后端(若登录)+ localStorage(离线) 3. 同步 — 登录时合并本地收藏与服务器;切换时写两者 4. 列表视图 — /favorites 页显已存项,按存日期排 5. 空状态 — "尚无收藏 — 点任何项的 ☆ 保存" 含浏览 CTA 6. 限制 — 上限 1000 收藏;超则建议文件夹/集合 6. 导出 — 让用户导出收藏(CSV/JSON)使其不感锁定 7. 移除 — 从列表视图(滑动或垃圾桶图标)取消收藏,非仅项页

示例

// useFavorites — 乐观切换、双存储 function useFavorites(userId?: string) { const [ids, setIds] = useState<Set<string>>(() => loadLocal()); const toggle = (id: string) => { const next = new Set(ids); next.has(id) ? next.delete(id) : next.add(id); // 乐观 setIds(next); saveLocal(next); if (userId) api.put(`/users/${userId}/favorites`, { ids: [...next] }).catch(() => setIds(ids)); // 回滚 }; return { ids, toggle, isFav: (id) => ids.has(id) }; } // 星按钮 — 乐观、可访问 <button aria-pressed={isFav(id)} aria-label={isFav(id) ? "从收藏移除" : "加到收藏"} onClick={() => toggle(id)} > <StarIcon filled={isFav(id)} /> </button> // 空状态 function FavoritesEmpty() { return ( <div> <h2>尚无收藏</h2> <p>点任何项的 ☆ 稍后保存。</p> <Link to="/browse">浏览项</Link> </div> ); }

常见问题

  • ⚠无离线存储 — 登出或断网时收藏消失,用户感背叛
  • ⚠空状态仅 '无收藏' — 无指引,用户不知如何加项
  • ⚠登录无合并 — 本地收藏被服务器覆写或反之,项丢

最佳实践

  • ✓双存储(localStorage + 服务器)— 离线工作、登录同步、跨设备存活
  • ✓乐观切换含回滚 — 即时反馈,服务器失败时回退
  • ✓设计有用空状态 — 解释如何加收藏、链到浏览

常见问题解答