第 40 课:任务详情抽屉里的编辑 / 删除联动强化

第 40 课:任务详情抽屉里的编辑 / 删除联动强化

这一课我们继续沿着"任务管理页主线"往前推,把上一课已经更像真实后台的 任务详情抽屉 再补上两个非常常见的后台交互能力:

  • 从详情抽屉直接进入编辑
  • 删除当前详情任务后,自动切到相邻任务

同时还要保证:

  • 编辑保存后,详情上下文不要丢
  • 删除后,详情抽屉不要留在一条已经不存在的任务上
  • 这些联动逻辑可以被单元测试稳定验证
  • 页面层、E2E 和文档一起跟上

这一课一句话在做什么?

这一课本质上是在做:

让任务详情抽屉从"只能看"的上下文面板,升级成"能继续推进编辑与删除流程"的真实后台工作入口。

这一步很关键。

因为真实后台里,用户不会只打开详情看一眼就回列表。

更常见的是:

  1. 先在列表里打开详情
  2. 在详情里发现字段要改
  3. 直接点编辑
  4. 或者确认这条记录应该删掉
  5. 操作完成后,页面还要保持连贯

所以这节课练的不是单个按钮,而是:

详情上下文和页面级增删改流程之间,怎样保持体验连续。


这次要解决的两个真实后台问题

1. 从详情里去编辑,保存后详情不能丢

如果用户是在详情抽屉里点了 编辑任务

  • 编辑弹窗打开前,通常要先把详情抽屉关掉
  • 不然两个覆盖层会叠在一起

但如果只是简单关掉详情,你会遇到一个体验问题:

  • 编辑保存成功了
  • 用户却回到了"没有详情上下文"的列表页

这很割裂。

更合理的体验是:

  • 如果编辑入口来自当前详情任务
  • 保存后就自动把详情抽屉重新打开到这条任务

这就是这一课新增的第一条联动。

2. 删除当前详情任务后,详情不能悬空

如果用户正在看第 5 条任务详情,然后直接在抽屉里点 删除任务,删除成功后会有两个风险:

  • 抽屉里还残留刚被删掉的内容
  • 地址栏和页面状态还指向已经不存在的任务

真实后台通常会这样处理:

  • 优先切到当前上下文里的下一条任务
  • 如果没有下一条,就退到上一条
  • 如果前后都没有了,就关闭详情抽屉

这就是这一课新增的第二条联动。


这节课最关键的设计结论

1. 详情联动决策可以先抽成纯函数

这次没有把所有判断都直接堆在 TasksView.vue 里。

而是先抽出了两个纯函数:

  • getTaskDetailIdToRestoreAfterEdit
  • getTaskDetailDeleteFallbackId

它们分别只做一件事:

  1. 判断这次编辑保存后要不要恢复详情
  2. 判断当前详情任务删除后应该跳到哪一条

这很重要。

因为页面层最容易越来越长、越来越难测。

把"纯判断"先抽出来以后:

  • 单元测试更直接
  • 页面层代码更清楚
  • 后面改规则时也更安全

2. 页面层负责协调,不让展示层接管业务状态

这一课的联动最终仍然放在:

  • src/views/TasksView.vue

而不是塞回:

  • TaskDetailDrawer.vue

原因很简单:

  • 抽屉组件只知道"用户点了编辑 / 删除"
  • 真正的页面上下文在页面层
  • 编辑弹窗状态也在页面层
  • 当前详情任务状态也在页面层

所以真正适合做协调的是页面层。

这体现的是一个很重要的后台前端原则:

入口可以在组件里,但跨区域联动应该交给页面层统一调度。

3. 删除后的跳转,应该基于当前筛选 + 排序上下文

这次删除当前详情任务后,不是随便找一条任务顶上来。

而是基于:

  • 当前筛选结果
  • 当前排序结果

也就是当前详情导航真正使用的那份上下文。

所以规则才会是:

  • 当前上下文中优先下一条
  • 没有下一条就上一条
  • 都没有就关闭

这说明一个关键点:

详情抽屉的联动,应该跟详情导航使用同一份上下文。


这次主要改了哪些文件?

这一课核心涉及这些文件:

  1. src/utils/taskDetailLinkage.ts
  2. src/utils/__tests__/taskDetailLinkage.spec.ts
  3. src/views/TasksView.vue
  4. e2e/pages/TasksPage.ts
  5. e2e/app.spec.ts
  6. docs/README.md

另外新增了本节文档:

  • docs/40-task-detail-drawer-edit-delete-linkage.md

src/utils/taskDetailLinkage.ts 里学什么?

这是这一课最值得你反复看的一个小文件。

它体现的是:

先把联动规则写清楚,再把它接回页面。

getTaskDetailIdToRestoreAfterEdit

这个函数只回答一个问题:

当前这次编辑保存后,要不要把详情抽屉恢复回来?

规则非常明确:

  • 如果当前详情任务 id 和编辑目标任务 id 相同
  • 就返回这条任务 id
  • 否则返回 null

也就是说:

  • 从当前详情里进入编辑,保存后恢复
  • 从列表别处进入编辑,不恢复当前详情

getTaskDetailDeleteFallbackId

这个函数只回答另一个问题:

当前详情任务删掉后,详情抽屉应该跳到哪一条?

规则是:

  1. 在当前导航上下文里先找到要删除的任务位置
  2. 优先返回下一条
  3. 没有下一条再返回上一条
  4. 如果前后都没有,就返回 null

这两个函数本质上都在表达:

页面联动先做成"输入明确、输出明确"的纯决策。


src/utils/__tests__/taskDetailLinkage.spec.ts 里学什么?

这一课的单元测试不是测页面,不是测 DOM,而是直接测规则。

主要覆盖了两类场景:

1. 编辑恢复详情

验证:

  • 当前详情任务和编辑任务相同时,会返回对应 id
  • 两者不同时,会返回 null
  • 当前根本没有详情时,也会返回 null

2. 删除后的回退目标

验证:

  • 删除中间项时优先跳到下一条
  • 删除最后一项时退到上一条
  • 只剩一项时返回 null
  • 删除目标不在当前上下文里时也返回 null

你要重点学会的是:

复杂联动不一定一上来就写组件测试,很多时候先把规则拆成纯函数测试,成本更低、稳定性更高。


src/views/TasksView.vue 里学什么?

这一课页面层主要多了 4 组思路。

1. 记录"编辑后是否恢复详情"的临时状态

页面层新增了:

  • taskDetailIdToRestoreAfterEdit

它的作用不是长期状态,而是:

  • 这一次编辑流程里的临时上下文

这说明:

不是所有状态都要进 composable 或 store。

有些只服务于当前一次交互流程的状态,放页面层 ref 就够了。

2. 打开编辑前先判断是否需要恢复详情

handleOpenEditTask 里:

  • 先调用 getTaskDetailIdToRestoreAfterEdit
  • 再关闭当前详情抽屉
  • 最后打开编辑弹窗

这一步做的是:

先记住要不要恢复,再切换 UI。

顺序不能反。

如果先关详情再判断,就会丢掉上下文依据。

3. 保存编辑后按条件恢复详情

handleUpdateTask 里:

  • 先暂存本次是否需要恢复详情
  • 再执行真正的更新
  • 如果需要恢复,就去最新任务数组里重新找这条任务
  • 找到后重新打开详情抽屉
  • 最后清空临时状态

这里有个很重要的细节:

恢复详情时,不能偷懒复用旧对象引用,而要从最新任务数组里重新取。

这样才能保证抽屉拿到的是更新后的最新任务数据。

4. 删除当前详情任务后维护详情上下文

handleDeleteTask 里:

  • 先判断删的是不是当前详情任务
  • 如果是,就先根据 sortedTasks 预计算删除后的目标任务 id
  • 删除成功后,再决定:
    • 切到相邻任务
    • 或关闭详情抽屉

这里最值得记住的是:

先算回退目标,再删数据。

因为删完以后,原来的位置信息可能就没有了。


为什么这里用 sortedTasks,而不是 paginatedTasks

这是这一课非常值得你理解的一点。

这次删除后的相邻跳转,使用的是:

  • sortedTasks

也就是:

  • 当前筛选结果
  • 当前排序结果
  • 但还没有被分页切片

为什么不用 paginatedTasks

因为详情导航本来就不是"当前页上一条 / 下一条"。

前面几课已经确定过:

详情导航上下文,应该基于完整筛选结果,而不是当前分页切片。

所以这节课删除联动沿用同一套上下文,逻辑才一致。


E2E 这次补了什么?

这一课在 e2e/pages/TasksPage.ts 里新增了两个页面对象方法:

  • openEditTaskFromDetailDrawer
  • openDeleteDialogFromTaskDetail

这样测试代码就能直接表达:

  • 从详情里编辑
  • 从详情里删除

而不是每次都重新写底层按钮定位。

e2e/app.spec.ts 里新增了两条测试:

1. user can edit a task from detail drawer and reopen same detail after save

这条测试验证:

  1. 打开第 4 条任务详情
  2. 从详情里进入编辑
  3. 修改标题并保存
  4. 详情抽屉自动回到同一条任务
  5. 地址栏里的 taskId 仍然保持正确
  6. 列表里的任务标题也同步更新

2. user can delete current detail task and jump to adjacent detail within current filtered results

这条测试验证:

  1. 先筛到 待开始 任务子集
  2. 打开中间那条第 5 条任务详情
  3. 从详情里直接删除它
  4. 第 5 条任务从列表消失
  5. 详情抽屉自动切到第 6 条任务
  6. 位置摘要从 第 2 / 3 条 变成 第 2 / 2 条
  7. statustaskId 查询参数都保持正确

这两条 E2E 很像真实后台测试。

因为它们测的不只是一个按钮,而是:

  • 当前详情上下文
  • 弹窗流程切换
  • 地址栏同步
  • 删除后的页面回退

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

学完这一课,你不应该只记住"详情里多了编辑和删除入口"。

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

1. 页面联动要先把规则说清楚

先抽纯函数,再接 UI。

这是把复杂交互做稳的关键。

2. 跨区域协调适合放页面层

详情抽屉、编辑弹窗、任务列表、地址栏同步,这些都横跨多个区域。

真正适合统一协调的,是页面层。

3. 删除后的回退目标必须依赖当前上下文

不能"随便找下一条",而要用和详情导航一致的结果集。

4. 临时交互状态也需要认真设计

像"这次编辑保存后要不要恢复详情"这种状态虽然短暂,但如果不设计清楚,体验就会断。

相关推荐
河阿里2 小时前
Java八股:面试高频50
java·面试
胡志辉2 小时前
前端反调试:常见套路、识别方法与绕过思路
前端·安全
Mr.mjw2 小时前
vue中使用 postcss-px-to-viewport 插件实现多屏适配
javascript·vue.js·postcss
Rabitebla2 小时前
【数据结构】实现通讯录:基于C语言动态顺序表
c语言·开发语言·数据结构·算法
小谢小哥2 小时前
53-熔断降级详解
java·后端·架构
覆东流2 小时前
第6天:python综合练习——制作简易计算器
开发语言·后端·python
今儿敲了吗2 小时前
应用实战2:新闻列表
学习·算法
蛋白界小百灵2 小时前
AID蛋白磷酸化位点功能验证:从体外激酶实验到B细胞CSR模型
学习·生物技术·实验
waves浪游2 小时前
进程间通信(上)
linux·运维·服务器·开发语言·c++