第 38 课:任务列表里高亮当前正在查看详情的任务

第 38 课:任务列表里高亮当前正在查看详情的任务

这一课我们继续沿着"任务管理页主线"往下推进,把上一课已经做好的"任务详情抽屉上下文导航"再向真实后台体验推进一步。

这次的目标很明确:

  • 当你打开某条任务详情时,列表里对应任务要同步高亮
  • 这个高亮不只在表格里生效,还要在卡片视图、看板视图里都成立
  • 当你在详情抽屉里切到上一条 / 下一条时,高亮要跟着切换
  • 当你关闭详情抽屉时,高亮要立刻消失
  • 补上单元测试、E2E 测试和课程文档

这一课一句话在做什么?

这一课本质上是在做一件事:

让"当前正在查看哪条任务详情"这个页面上下文,反向影响列表的视觉反馈。

也就是说,详情抽屉不再只是"右边弹出来一块内容"。

它会开始和左边列表形成联动:

  • 详情在看谁
  • 列表就高亮谁
  • 详情切到谁
  • 列表就跟着切到谁
  • 详情关闭
  • 列表就清掉高亮

这是一种很典型的后台系统体验增强。


为什么真实后台里经常需要这种联动?

因为用户在后台里很少是"只看详情,不看列表"。

更常见的是:

  1. 先在列表里筛出一批任务
  2. 打开其中一条详情
  3. 处理一会儿后切到下一条
  4. 同时希望眼睛还能快速知道"当前处理的是列表里的哪一条"

如果没有高亮,用户很容易出现这几个问题:

  • 看着详情,不知道自己正在处理列表中的哪条记录
  • 在详情里切到下一条后,列表没有视觉跟进
  • 列表、详情像两套互不认识的系统

所以这节课练的,不只是"加一个背景色"。

真正练的是:

  • 页面上下文如何共享
  • 同一份状态如何驱动多个视图
  • 为什么后台里的"联动反馈"比"单点组件功能"更重要

这节课最关键的设计结论

1. 高亮状态不应该分散在三个视图里各自乱算

这次我们新增了一个共享工具文件:

  • src/components/tasks/taskDetailActiveHighlight.ts

里面只做两件事:

  • isTaskDetailActive(taskId, activeTaskId)
  • getTaskTableRowClassName(taskId, activeTaskId)

这说明一个重要原则:

同一条业务规则,如果会被多个视图同时使用,就应该优先抽成共享函数。

这样做的好处很直接:

  • 表格、卡片、看板用的是同一套"是否高亮"规则
  • 后面修规则时,不会三个地方各改一遍
  • 单元测试也可以直接先测纯函数,再测组件渲染

2. 页面状态继续留在页面层,而不是塞进子组件内部

这次三种列表视图都没有自己维护"我当前高亮谁"。

它们都只是接收:

  • activeTaskId

然后根据这个 id 去决定:

  • 我该不该高亮这一行
  • 我该不该高亮这张卡片

这说明:

子组件负责消费状态,页面层负责拥有状态。

这里的状态来源仍然是:

  • useTasksPage.ts
  • TasksView.vue

这和前面几课一直强调的分层原则是完全一致的。

3. 三种视图的高亮表现可以不同,但判定标准必须相同

这一课里:

  • 表格视图用行 class 高亮
  • 卡片视图用卡片 class 和 data-detail-active
  • 看板视图也用卡片 class 和 data-detail-active

它们的视觉实现不同,是合理的。

因为三种视图的 DOM 结构本来就不同。

但是它们判定"当前是不是详情任务"的标准必须一样。

这也是为什么这次要抽共享判断函数。


这次主要改了哪些文件?

这一课主要改了这些地方:

  1. src/components/tasks/taskDetailActiveHighlight.ts
  2. src/views/TasksView.vue
  3. src/components/tasks/TaskTable.vue
  4. src/components/tasks/TaskCardList.vue
  5. src/components/tasks/TaskKanbanBoard.vue
  6. src/components/tasks/__tests__/taskDetailActiveHighlight.spec.ts
  7. src/components/tasks/__tests__/taskDetailActiveViews.spec.ts
  8. e2e/pages/TasksPage.ts
  9. e2e/app.spec.ts
  10. docs/README.md

另外新增了本节文档:

  • docs/38-task-list-highlight-active-detail-task.md

TasksView.vue 里学什么?

文件:

  • src/views/TasksView.vue

这次页面层做的事情不复杂,但非常关键:

  1. 继续从 useTasksPage() 拿到 activeTaskDetailId
  2. 把它分别传给三个列表组件
  3. 让三种视图都共享同一个"当前详情任务 id"

也就是说,这次页面层做的不是"写新逻辑",而是"把已有页面上下文继续分发给更多视图"。

这很像真实项目里的迭代方式:

  • 先把状态设计对
  • 再让更多组件接入这份状态

这比每次新功能都重新发明一套状态结构健康得多。


TaskTable.vue 里学什么?

文件:

  • src/components/tasks/TaskTable.vue

这一课里,表格最重要的变化是:

  • 接收 activeTaskId
  • 行 class 改成通过共享函数统一生成

现在表格行 class 不再是只拼:

  • task-table-row
  • task-table-row--task-id-xxx

而是会在命中当前详情任务时额外补上:

  • task-table-row--active-detail

这节课很适合你理解一个后台前端的常见技巧:

样式 class 不只是给 CSS 用的,它也经常是测试稳定定位和状态表达的一部分。

这里的 task-table-row--task-id-xxx 方便 E2E 精准定位。

task-table-row--active-detail 则负责表达"当前详情高亮中"。


TaskCardList.vueTaskKanbanBoard.vue 里学什么?

文件:

  • src/components/tasks/TaskCardList.vue
  • src/components/tasks/TaskKanbanBoard.vue

这两个组件这次都做了同一类升级:

  • 接收 activeTaskId
  • 复用共享高亮判断函数
  • 把当前详情任务映射成 class 和 data-detail-active

其中 data-detail-active 很值得你记住。

因为它代表一种很实用的工程习惯:

当视觉状态需要被测试稳定读取时,可以用 data-* 属性把"真实状态"明确暴露给测试。

这样测试就不必过度依赖:

  • 背景色
  • 阴影
  • 某个深层 DOM 结构

而是可以直接断言:

  • data-detail-active="true"
  • data-detail-active="false"

这会比只看样式类更稳。


单元测试这次测了什么?

文件:

  • src/components/tasks/__tests__/taskDetailActiveHighlight.spec.ts
  • src/components/tasks/__tests__/taskDetailActiveViews.spec.ts

这次单元测试分成两层。

1. 先测纯函数规则

taskDetailActiveHighlight.spec.ts 里,主要验证了:

  • taskId 和 activeTaskId 相等时会返回高亮
  • activeTaskId 为空时不会误判
  • 表格行 class 会始终带稳定基础 class
  • 命中当前详情任务时会额外带上高亮 class

这类测试的价值是:

  • 规则变化时能最早发现问题
  • 不依赖 DOM
  • 失败时定位很直接

2. 再测组件是否把规则变成真实 DOM 状态

taskDetailActiveViews.spec.ts 里,主要验证了:

  • 卡片视图会给当前详情任务卡片加高亮 class
  • 卡片视图会同步输出 data-detail-active
  • 看板视图会给当前详情任务卡片加高亮 class
  • activeTaskId 变化或清空时,DOM 状态会跟着更新

这类测试练的是:

  • props 驱动视图
  • DOM 状态如何反映业务状态
  • 为什么要把"规则测试"和"渲染测试"分开

E2E 这次测了什么?

文件:

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

这次我们给页面对象补了 6 个断言方法:

  • expectTaskRowActiveById
  • expectTaskRowInactiveById
  • expectTaskCardActiveById
  • expectTaskCardInactiveById
  • expectTaskKanbanCardActiveById
  • expectTaskKanbanCardInactiveById

然后补了一条新的完整 E2E:

  • user can highlight current detail task across task list views

这条测试链路会验证:

  1. 打开第 4 条任务详情
  2. 表格行高亮生效
  3. 切到卡片视图后,对应卡片继续高亮
  4. 切到看板视图后,对应看板卡片继续高亮
  5. 在详情抽屉里切到下一条任务
  6. 高亮从第 4 条迁移到第 5 条
  7. 关闭详情抽屉
  8. 高亮彻底消失
  9. 切回表格视图后不残留旧高亮

这条 E2E 很有代表性。

因为它测的已经不只是"一个组件有没有渲染出来",而是:

  • 页面上下文
  • 多视图联动
  • 详情切换
  • 关闭后的状态清理

这就是越来越像真实后台系统测试的地方。


你现在真正应该学会什么?

学完这一课,你不应该只记住"加了高亮样式"。

更重要的是理解下面 4 件事:

1. 详情状态本身就是一种页面上下文

activeTaskDetailId 不只是"右边抽屉显示谁"。

它还可以驱动左边列表的反馈。

这说明页面状态不是只能服务单个组件。

它经常会跨组件、跨区域复用。

2. 同一规则最好只有一个来源

这次把"当前详情任务是否命中"抽成共享函数,目的是避免:

  • 表格自己算一套
  • 卡片自己算一套
  • 看板自己再算一套

一旦规则分散,后面就很容易出现"一个视图亮,一个视图不亮"的问题。

3. 测试最好分层

这次的测试结构很典型:

  • 纯函数测规则
  • 组件测渲染
  • E2E 测真实交互链路

这是非常值得你建立的工程习惯。

4. 真正的后台体验来自联动,而不是单点功能堆叠

前几课我们做了:

  • 列表筛选
  • 视图切换
  • 详情抽屉
  • 上一条 / 下一条

这一课开始把这些能力真正连起来。

所以这节课的价值,不在"功能数量增加了多少"。

而在"已有功能之间开始互相配合"。


这一课完成后,任务页更像真实后台了吗?

是的,而且更像了很多。

现在这个任务页已经不只是:

  • 能筛选
  • 能分页
  • 能切换视图
  • 能看详情

而是开始具备一种更真实的后台工作感:

  • 你在详情里处理哪条任务
  • 列表就明确告诉你它是谁
  • 你切到下一条
  • 列表就跟着迁移视觉焦点
  • 你关闭详情
  • 列表就回到普通浏览状态

这已经很接近真实后台里的"列表 <-> 详情联动体验"了。

相关推荐
澈2071 小时前
构造函数与析构函数完全指南
开发语言·c++
W23035765732 小时前
C++ 高并发线程池实战(二):动态缓存线程池 + 调用者运行拒绝策略完整版实现
开发语言·c++·缓存
气宇轩昂固执狂2 小时前
01-初识C语言
c语言·开发语言
t***5442 小时前
如何在 Dev-C++ 中使用 Clang 编译器
开发语言·c++
anOnion2 小时前
构建无障碍组件之Spinbutton Pattern
前端·html·交互设计
lwf0061642 小时前
逻辑回归学习笔记-数学直接解回归方程
笔记·学习·逻辑回归
程序员Better2 小时前
前端成功转型AI全栈,我踩过的坑都替你填上了
前端·后端·ai编程
兔子零10242 小时前
GPT-5.5 与 DeepSeek-V4:大模型竞争的本质,正在从“谁更强”变成“谁让成本更低”
前端·javascript·后端
Daybreak2 小时前
幽灵依赖:本地跑得好好的,线上部署却炸了
前端