当前位置: 首页 > news >正文

第 32 课:任务卡片按状态分组与本地持久化

第 32 课:任务卡片按状态分组与本地持久化

这一课我们继续沿着“任务管理页个人工作台偏好”主线往下推进。

上一课我们已经让任务列表支持:

  • 表格视图
  • 卡片视图

这一课继续把卡片视图做得更像真实后台系统:

让当前页卡片支持“平铺显示 / 按状态分组”两种组织方式,并把这份偏好持久化到 localStorage。


这节课一句话在做什么?

这一课我们完成了 6 件事:

  1. 给任务卡片列表新增了平铺显示 / 按状态分组两种分组模式。
  2. 把当前分组模式保存到了localStorage
  3. 刷新任务页后,卡片分组模式会自动恢复。
  4. 让卡片分组只作用于当前页任务,不改筛选结果和分页语义。
  5. 保持卡片里的勾选、编辑、删除、字段显隐继续可用。
  6. 补上了单元测试、E2E 测试和课程文档。

这一课最重要的设计结论

这一课最重要的结论是:

卡片分组方式属于展示偏好,不属于业务筛选条件。


为什么“按状态分组”不是筛选?

很多初学者第一次做这个功能时,很容易把它误写成:

  • 再加一个筛选条件
  • 或者干脆改变任务结果集

但这其实是不对的。

1. 分组不会改变命中的任务集合

无论当前卡片列表是:

  • 平铺显示
  • 按状态分组

命中的任务集合都没有变。

它不会改变:

  • keyword
  • statusFilter
  • priorityFilter
  • sortOption
  • currentPage

它改变的是:

  • 当前页任务怎么分块展示
  • 同一批卡片怎么更容易阅读

所以它本质上仍然是:

  • 展示偏好

而不是:

  • 业务状态

2. 分组偏好更适合进localStorage

为什么这次也没有把“分组模式”写进 URL?

因为 URL 更适合表达:

  • 这次访问到底想看哪一批数据

而卡片分组模式更像:

  • 我个人更习惯怎么读这批卡片

这种偏好应该满足的是:

  • 刷新后保留
  • 下次进入页面自动恢复
  • 不污染分享链接

所以这一课继续把它放进了:

  • localStorage

3. 分组应该作用于“当前页切片结果”

这是这节课最值得你真正想清楚的点。

当前任务页已经有一套稳定的数据流:

  1. 原始任务
  2. 筛选
  3. 排序
  4. 分页切片
  5. 渲染当前页

这一课我们没有把分组插到分页前面,而是放在:

当前页切片之后

也就是:

  1. 先得到paginatedTasks
  2. 再把paginatedTasks按状态分区

这样做的好处是:

  • 不会破坏现有分页语义
  • 不会让页码和实际看到的数据范围打架
  • 更符合“这是当前页展示方式”的定位

这在真实后台里非常重要。


这一课在useTasksPage里做了什么?

文件:

  • src/composables/useTasksPage.ts

这次新增的核心状态仍然放在任务页组合式函数里,因为:

  • 分组模式是页面级偏好
  • 不是某个卡片组件自己的临时状态

1. 新增了分组模式类型、默认值和本地存储 key

这次新增了:

  • TaskListGroupingMode
  • TaskListGroupingModeOptionItem
  • TaskListGroupSection
  • DEFAULT_TASK_LIST_GROUPING_MODE
  • TASK_LIST_GROUPING_MODE_STORAGE_KEY

这套设计继续沿用前几课已经反复训练过的工程模式:

  • 先定义稳定类型
  • 再定义默认值
  • 再定义本地存储 key
  • 最后把读取、标准化、写回流程补齐

2. 新增了“读取 -> 校验 -> 标准化 -> 写回”的分组偏好流程

这次新增了这几类函数:

  • isTaskListGroupingMode
  • normalizeTaskListGroupingMode
  • readPersistedTaskListGroupingMode
  • persistTaskListGroupingMode

它们的职责很清楚:

  1. 从本地存储读出旧值
  2. 判断这个旧值是不是合法
  3. 非法就回退到none
  4. 再通过watch(..., { immediate: true })把标准化结果写回去

这套流程不是“麻烦”,而是工程必要动作。

因为真实项目里本地存储经常会遇到:

  • 历史旧值
  • 手动篡改
  • 老版本遗留数据

所以不能直接相信它。


3. 新增了页面级分组状态和行为

这次新增的页面级状态主要有:

  • taskListGroupingMode
  • taskListGroupingModeOptions
  • paginatedTaskGroups
  • handleTaskListGroupingModeChange()

最值得你注意的是:

paginatedTaskGroups不是基于全部筛选结果生成的,而是基于 paginatedTasks 生成的。`

这说明我们一直在坚持:

  • 分页决定“当前页有哪些任务”
  • 分组决定“当前页这些任务怎么组织展示”

这两个层次不能混。


4. 新增了分组结果生成函数

这次新增了:

  • createTaskListGroupSections(taskList)

它做的事情很简单,但很典型:

  1. 按稳定状态顺序遍历
  2. 把属于同一状态的任务收集起来
  3. 只保留非空分组
  4. 输出统一结构给卡片组件渲染

这里有两个很重要的工程细节:

  • 分组顺序固定为状态顺序,而不是随机顺序
  • 分组内任务顺序继续保留当前页原有排序结果

这样页面行为才稳定、可预测、可测试。


这一课在界面层做了什么?

文件:

  • src/components/tasks/TaskListGroupingSettings.vue
  • src/components/tasks/TaskCardList.vue
  • src/views/TasksView.vue

1. 新增了TaskListGroupingSettings

这个组件负责:

  • 展示“平铺显示 / 按状态分组”切换入口
  • 展示当前分组模式摘要
  • 通过emit把切换动作抛给父层

它没有自己处理:

  • localStorage
  • 分组计算
  • 页面状态

它仍然只做:

  • UI
  • 用户输入

这说明你现在已经在逐步建立一个很重要的前端边界意识:

输入组件负责交互,页面级 composable 负责状态和持久化。


2.TasksView.vue负责页面级编排

这次页面层做了两件关键事情:

  1. 当当前列表是卡片视图时,才显示TaskListGroupingSettings
  2. taskListGroupingModepaginatedTaskGroups传给TaskCardList

这里非常值得学习:

页面层不是在“堆组件”。

它真正做的是:

  • 条件编排
  • 状态分发
  • 多个展示能力之间的协调

这就是页面层最核心的职责。


3.TaskCardList.vue升级成“平铺 / 分组”双模式

这次TaskCardList没有改成两个完全不同的组件,而是做了一次很典型的“模板统一化”处理:

  • 先把平铺模式整理成一个假的单分区
  • 再把按状态分组模式整理成真实多分区
  • 模板统一循环渲染cardSections

这样做的好处是:

  • 少写一套重复模板
  • 单卡片结构只维护一份
  • 勾选、编辑、删除逻辑不用拆两份

这是一种很实用的前端技巧:

先把数据结构统一,再让模板保持简单。


这一课最值得你学会的前端思想

1. “分组”是展示组织,不是数据过滤

很多后台系统都会同时出现:

  • 筛选
  • 排序
  • 分页
  • 分组

你一定要学会把它们分开:

  • 筛选:决定保留哪些数据
  • 排序:决定数据先后顺序
  • 分页:决定当前页取哪一段
  • 分组:决定当前这一段怎么组织展示

只要这一层你分清楚,后面做:

  • 看板分列
  • 时间线分段
  • 日志按日期分组

都会顺很多。


2. 页面级状态应该高于展示组件

这一课我们仍然没有把分组模式状态塞进TaskCardList组件内部。

因为它不是“这个组件自己一时兴起的状态”,而是:

  • 页面级偏好
  • 要持久化
  • 要被页面层协调

这说明真正稳定、真正重要的状态,应该放在:

  • 页面级 composable

而不是:

  • 最终渲染组件内部

3. 同一批数据可以先分页,再分组

很多初学者会天然以为:

  • 先分组,再分页

但真实后台里不一定这样。

这一课故意选择:

  • 先分页
  • 再分组

是为了让你认识到:

前端的数据处理顺序,不是固定教条,而是由产品语义决定的。

当前这节课的产品语义是:

  • 分页仍然表示“当前页看到哪几条任务”
  • 分组只是“这几条任务怎么读起来更清楚”

所以先分页再分组是合理的。


这一课补了哪些测试?

1. 单元测试

文件:

  • src/composables/__tests__/useTasksPage.spec.ts

新增覆盖:

  • localStorage恢复合法卡片分组模式
  • 非法分组模式自动回退成none
  • 标准化结果写回本地存储
  • 切换分组模式后页面状态是否正确联动
  • paginatedTaskGroups是否只基于当前页任务生成

这一层主要验证:

  • 页面级偏好状态是否正确
  • 分组计算边界是否正确

2. E2E 测试

文件:

  • e2e/pages/TasksPage.ts
  • e2e/app.spec.ts

新增覆盖:

  • 切到卡片视图
  • 切到“按状态分组”
  • 断言卡片分组标题真实出现
  • 刷新页面
  • 再次断言分组模式和分组标题仍然保留

这一层主要验证:

  • 不只是状态值变了
  • 卡片列表结构也真的按状态分区了
  • 持久化偏好在真实浏览器里确实能恢复

这一课改了哪些文件?

  • src/types/task.ts
  • src/composables/useTasksPage.ts
  • src/components/tasks/TaskListGroupingSettings.vue
  • src/components/tasks/TaskCardList.vue
  • src/views/TasksView.vue
  • src/composables/__tests__/useTasksPage.spec.ts
  • e2e/pages/TasksPage.ts
  • e2e/app.spec.ts
  • docs/32-task-card-grouping-by-status-and-persistence.md
  • docs/README.md

这一课最值得你真正记住什么?

如果你只记住“多了一个按状态分组按钮”,那还不够。

你更应该记住下面这 6 点:

  1. 分组不等于筛选,分组只是展示组织方式。
  2. 展示偏好通常更适合放进localStorage,而不是 URL。
  3. 这节课的分组语义是“对当前页任务分组”,不是“对全部结果分组”。
  4. 页面级状态应该放在 composable,而不是塞进最终渲染组件内部。
  5. 当两种展示模式共享同一套卡片结构时,优先统一数据结构,而不是复制两套模板。
  6. 真正好的后台列表能力,不只是能点通,还要能持久化、可测试、边界清晰。

这一课的验证命令

完成后至少应该验证:

npmrun test:unit ----runnpmrun type-checknpmrun lintnpmrun test:e2e ----project=chromium

一句话总结

这一课真正要学会的是:

任务卡片“平铺显示 / 按状态分组”不是一个简单视觉开关,而是一种典型的后台展示偏好能力;你要学会把它和筛选、排序、分页分层处理,再用页面级状态、统一数据结构、条件编排和 localStorage 持久化把它做成真正可维护的任务页能力。

http://www.jsqmd.com/news/669536/

相关文章:

  • Windows Cleaner:终极免费开源工具,快速解决C盘爆红问题
  • 推荐系统常用指标NDCG含义及公式
  • 2026年本地工业通风降温/正负压通风降温/局部通风降温/通风降温管道优质供应商推荐 - 行业平台推荐
  • 力扣204
  • Hermes Agent 项目总览
  • Pixel Fashion Atelier部署教程:Mac M2/M3芯片通过MLX适配Stable Diffusion方案
  • 基于SpringBoot + Vue的社区互助系统
  • 2026年高精度浙江立式加工中心/立卧两用加工中心/加工中心/天车式加工中心厂家精选合集 - 品牌宣传支持者
  • 2026年口碑好的江苏减速机/江苏行星减速机优质厂家推荐榜 - 品牌宣传支持者
  • 2026年靠谱的连栋种植温室大棚/广东玻璃种植温室大棚推荐厂家精选 - 品牌宣传支持者
  • 图论——BFS搜索模板(python)
  • 2026年质量好的高压直流继电器/汽车继电器/小型继电器/信号继电器厂家选择推荐 - 行业平台推荐
  • win10、11系统磁盘空间不够,显示存储池占用,磁盘管理显示存储池分区,导致不能使用的解决方案
  • wan2.1-vae惊艳效果:2048×2048下1:1人脸特写——毛孔、睫毛、唇纹级细节
  • 2026年靠谱的浙江汽车空气悬挂/底盘空气悬挂高口碑品牌推荐 - 品牌宣传支持者
  • 2026年冲压车间岗位通风降温/工业通风降温厂家对比推荐 - 行业平台推荐
  • 后端接口必备:统一返回码设计,让系统更规范、协作更高效
  • 图论——求岛屿的最大面积(python)
  • 2026年质量好的南通钢丝绳电动葫芦/电动葫芦/南通环链电动葫芦/南通电动葫芦长期合作厂家推荐 - 行业平台推荐
  • 自指宇宙学研究大纲:存在如何通过自我描述而实在化(世毫九实验室原创理论)
  • A、B、C、D、E类IPv4地址划分和使用
  • 2026年口碑好的自动牵引绳/狗狗牵引绳/反光牵引绳厂家推荐与选型指南 - 行业平台推荐
  • 2026年比较好的宁波抽屉式模具架/宁波标准模具架/金属模具架源头工厂推荐 - 品牌宣传支持者
  • AGI武器化临界点已至:全球7国军方内部评估报告泄露,5个致命伦理漏洞亟待封堵
  • 2026年知名的电渗析开关电源/宁波电渗析开关电源/电催化氧化开关电源多家厂家对比分析 - 行业平台推荐
  • OBS StreamFX 终极指南:免费打造专业级直播效果的完整方案
  • 忍者像素绘卷真实作品展示:16色限制下高表现力角色原画集
  • 2026年口碑好的南通移动式升降平台/南通升降平台/移动式升降平台/升降平台主流厂家对比评测 - 行业平台推荐
  • 2026年热门的温室大棚骨架批发/温室大棚骨架/连体温室大棚骨架厂家综合对比分析 - 品牌宣传支持者
  • Qt——软件开发流程简介