第 31 课:任务列表视图模式切换与本地持久化
第 31 课任务列表视图模式切换与本地持久化这一课我们继续沿着“任务管理页个人工作台偏好”主线往下推进。这次做的不是新的筛选条件也不是新的排序规则而是后台系统里非常常见的一种列表体验能力让同一批任务在“表格视图”和“卡片视图”之间自由切换。很多真实后台都会有类似功能表格视图卡片视图列表视图看板视图这一步非常适合学习因为它会逼你真正想清楚什么是业务数据什么是列表表现形式什么适合进 URL什么适合进localStorage这节课一句话在做什么这一课我们完成了 6 件事给任务页新增了表格视图 / 卡片视图两种主列表模式。把当前视图模式保存到了localStorage。刷新任务页后当前视图模式会自动恢复。新增了TaskCardList让任务列表真正支持卡片化展示。让卡片视图继续复用当前页的选择状态、编辑、删除和字段显示配置。补上了单元测试、E2E 测试和课程文档。这一课最重要的设计结论这一课最重要的结论是列表“看成什么样”属于展示偏好不属于业务筛选条件。为什么1. 视图模式不会改变任务结果集无论你把任务页切成表格视图卡片视图命中的任务集合都没有变。它不会改变keywordstatusFilterpriorityFiltersortOptioncurrentPage它改变的是一条任务以什么结构展示字段如何排布用户阅读同一批数据的方式所以它本质上属于展示偏好而不是业务筛选状态2. 展示偏好更适合放到localStorage为什么视图模式不写进 URL因为 URL 更适合表达这次访问到底想看哪一批数据而视图模式更像我个人更习惯用哪种方式看这批数据这种信息更适合刷新后保留下次进入页面自动恢复不污染分享链接所以这一课继续把它放进了localStorage3. 同一批数据可以有不同“表现层”这一课非常值得你建立一个新的前端意识数据本身和数据怎么呈现不是一回事。同一条任务在表格里更像“多列比较项”在卡片里更像“独立信息块”这说明前端页面经常要同时处理两层问题我现在要展示哪些数据我准备用什么形态展示这些数据把这两层分清楚后面你才能继续做看板视图时间线视图主从布局多端适配这一课在useTasksPage里做了什么文件src/composables/useTasksPage.ts这次仍然把核心状态放在任务页组合式函数里因为列表视图模式属于页面级偏好状态它不是某一个子组件自己的瞬时状态。新增了类型、默认值和本地存储 key这次新增了TaskListViewModeTaskListViewModeOptionItemDEFAULT_TASK_LIST_VIEW_MODETASK_LIST_VIEW_MODE_STORAGE_KEY这套设计延续了前几课的习惯用类型限制合法值范围用默认值约束初始行为用稳定 storage key 承接持久化新增了“读取 - 校验 - 标准化 - 写回”的视图偏好流程这一课继续沿用我们前面反复训练过的模式从localStorage读取列表视图模式判断它是不是合法值非法值回退到table用watch(..., { immediate: true })把标准化结果重新写回这是非常典型的工程动作因为本地存储经常会遇到老版本数据手动篡改非法写入所以不能直接把本地值当真。新增了页面级状态和动作函数这次新增了几个关键能力taskListViewModetaskListViewModeOptionsisTaskTableViewhandleTaskListViewModeChange()这里最值得你注意的是命名。我们不是只在写一个字符串 ref而是在表达当前列表主视图是什么当前页面是不是表格模式用户现在要切换列表形态这类命名会让 composable 越来越像真正的“页面领域层”。这一课在界面层做了什么文件src/components/tasks/TaskListViewModeSwitch.vuesrc/components/tasks/TaskCardList.vuesrc/views/TasksView.vuesrc/components/tasks/TaskColumnSettings.vue1. 新增了TaskListViewModeSwitch这个组件负责展示“表格视图 / 卡片视图”切换入口展示当前视图模式摘要通过emit把切换动作抛给父层注意它没有自己读写localStorage。它仍然只做UI用户输入而不是业务状态持久化。2. 新增了TaskCardList这是这一课最重要的新增组件。它不只是“换个壳”而是真正把任务列表实现成了卡片视图。这个组件里继续保留了这些真实能力加载态错误态空状态单条勾选编辑删除字段显隐配置这一步很重要因为它说明“视图模式切换”不是简单切 CSS而是同一套页面状态驱动两套不同的列表表现组件。3.TasksView.vue负责切换表格组件和卡片组件页面层这次做了 3 件关键事情接入视图模式切换组件根据当前模式决定渲染TaskTable还是TaskCardList用统一的外层容器标记当前data-view-mode这一层非常值得学习因为页面层再次承担了组件编排状态分发列表展示协调这正是页面层最该做的事。4. 字段显示配置升级成“跨视图生效”这一课顺手把“显示列”能力继续往前推进了一步不再只影响表格也影响卡片视图里显示哪些字段这很像真实后台系统里的做法。虽然按钮还叫“显示列”但本质上它已经更接近列表字段显示配置这说明一个功能一开始可能看起来只服务某个视图但当系统演进后它的语义会自然升级。这一课最值得你学会的前端思想1. 条件渲染不是“偷懒”而是视图编排能力在TasksView.vue里我们根据当前模式决定渲染TaskTableTaskCardList这不是简单的 if/else。它体现的是同一页共享同一套页面状态不同组件负责不同展示结构这就是前端非常核心的“视图编排”能力。2. 组件复用不一定是“一个组件做所有事”很多初学者一看到“两个视图”就会想能不能硬塞进同一个组件里但真实工程里更稳的做法往往是共享状态分开表现层组件所以这次我们没有把TaskTable.vue改成超级大组件而是新增了TaskCardList.vue这其实更符合长期可维护性。3. 页面级选择状态可以跨不同视图复用这一课还有一个很重要的点虽然任务列表有了两种表现形式但选择状态仍然保留在页面级 composable 中。所以无论是表格视图卡片视图都可以继续共享selectedTaskIds批量操作栏跨页选择策略这说明真正稳定的状态应该放在比展示组件更高的层。这一课补了哪些测试1. 单元测试文件src/composables/__tests__/useTasksPage.spec.ts新增覆盖从localStorage恢复合法列表视图模式非法视图模式自动回退成table标准化结果写回本地存储切换列表视图模式后同步更新页面状态isTaskTableView是否正确联动这一层主要验证页面级偏好状态是否正确持久化边界是否正确2. E2E 测试文件e2e/pages/TasksPage.tse2e/app.spec.ts新增覆盖点击“卡片视图”按钮断言列表区域data-view-modecard断言默认任务真的出现在卡片里刷新页面再次断言仍然保持卡片视图这一层主要验证真实 UI 是否能点通不只是状态变了列表表现形式也真的切换了偏好是否真的跨刷新保留这一课改了哪些文件src/types/task.tssrc/composables/useTasksPage.tssrc/components/tasks/TaskListViewModeSwitch.vuesrc/components/tasks/TaskCardList.vuesrc/components/tasks/TaskColumnSettings.vuesrc/views/TasksView.vuesrc/composables/__tests__/useTasksPage.spec.tse2e/pages/TasksPage.tse2e/app.spec.tsdocs/31-task-list-view-mode-switch-and-persistence.mddocs/README.md这一课最值得你真正学会什么如果你只记住“多了一个表格/卡片切换按钮”那还不够。你更应该记住下面这 6 点同一批数据可以有不同的表现层结构。视图模式属于展示偏好不属于筛选条件。展示偏好通常更适合放进localStorage而不是 URL。页面级状态应该高于具体展示组件这样同一套状态才能驱动多种视图。组件复用不一定是“一个组件做完全部”很多时候是“共享状态 分开视图组件”。真正好的视图切换不是值变了而是页面真的切到了另一种结构并且可测试、可持久化。这一课的验证命令完成后至少应该验证npmrun test:unit ----runnpmrun type-checknpmrun lintnpmrun test:e2e ----projectchromium