Notesnook 任务清单(Task List)完整指南:创建、进度追踪、子任务嵌套与只读锁定的编辑器实现
前端移动开发桌面应用应用安全【免费下载链接】notesnookA fully open source end-to-end encrypted note taking alternative to Evernote.项目地址https://gitcode.com/gh_mirrors/no/notesnook点击查看免费下载任务清单Task List是 Notesnook 富文本编辑器中内嵌于笔记正文的待办列表组件每个清单都随笔记一起保存并与其他内容一样经过端到端加密。本文以官方帮助文档为主线结合开源仓库中packages/editor的源码实现完整讲解任务清单的创建方式、进度追踪机制、标题与统计、子任务联动勾选、排序清理、拖拽重排以及只读锁定帮助你既能在桌面端、Web 与移动端熟练使用也能理解其底层 ProseMirror/Tiptap 扩展是如何工作的。任务清单是什么内嵌于笔记、随笔记加密任务清单不是一个独立的待办事项应用而是活在一个笔记里面的列表。这意味着你的检查清单和解释它的说明文字处在同一个文档中信息天然聚合不会出现笔记归笔记、清单归清单的割裂。由于清单是笔记内容的一部分它也和其他笔记内容一样经过端到端加密参见 数据是如何加密的只有你自己能读取。任务清单功能属于Essential 计划及以上详见 Plans limits。免费计划用户仍可使用简单的复选框清单Checklist在已有的项目符号列表里输入[]或者从工具栏选择{{checklist}}即可。从源码结构看任务清单在编辑器中被实现为两个相互配合的 Tiptap 扩展TaskListNode清单容器渲染ul.checklist与TaskItemNode清单条目两者都位于 packages/editor/src/extensions/task-list 和 packages/editor/src/extensions/task-item 目录。扩展通过 extension-imports.ts 注册进编辑器并在 index.ts 中对外导出。向笔记中添加任务清单桌面端 / Web将光标放在一个空行上点击工具栏中的Insert按钮选择{{taskList}}。移动端将光标放在一个空行上点按工具栏中的Insert按钮选择{{taskList}}。移动端的 Markdown 快捷输入默认开启因此直接在空行输入[]也能快速创建清单。快捷键与快捷输入快捷键CtrlShiftT一键切换任务清单。在源码 keybindings.ts 中该快捷键被定义为Mod-Shift-TMod在 Windows/Linux 上即 Ctrl在 macOS 上是 Cmd并注册到编辑器的键盘快捷键表里见 task-list.ts。Markdown 快捷输入在开启 Markdown 快捷输入 的前提下在空行输入[]即可生成清单条目。这条规则的底层是一个wrappingInputRule源码在 task-list.ts 中复用了 Tiptap 任务条目的inputRegex并在触发时先调用commands.clearNodes()重置节点格式再把选中内容转换为任务清单它还支持[x]这样的已勾选写法——末尾匹配到x时新建条目的checked属性会被置为true。工具栏入口工具栏中的任务清单按钮定义在 block.tsx通过editor.chain().focus().toggleTaskList().run()命令触发并通过editor.isActive(taskList)显示当前是否处于清单激活状态。追踪进度标题、计数与进度条每个任务清单顶部都有一个清单头header显示三项信息标题输入框每个清单创建时头部会带有一个标题栏你可以直接输入标题文字进度统计显示已完成/总数例如3/5进度条随着勾选进度自动填充视觉上直观反映完成比例。该头部由 component.tsx 中的TaskListComponent渲染。其实现细节可以说明三个关键机制进度条宽度样式中的width直接由Math.round((stats.checked / stats.total) * 100) %计算并带250ms ease-out的宽度过渡动画见 component.tsx统计数据来源清单节点携带stats属性结构为{ checked, total }见 task-list.ts。stats只渲染在根级清单上嵌套清单不会重复显示头部——组件通过isNested判断节点的父类型是否为TaskItem来决定是否渲染清单头见 component.tsx一键全选清单头左侧的复选框按钮用于整单勾选/取消全部任务底层调用toggleChildren(tr, node, !checked, parentPos)一次性改写所有条目。父子任务自动联动勾选任务清单的勾选状态具有自动联动逻辑勾选父任务会自动勾选其下所有子任务清空最后一个子任务会反向取消父任务的勾选状态。这套逻辑在源码中由一个名为task-list-state-management的 ProseMirror 插件实现见 task-list.ts对应两种场景Case 1父级驱动当某条任务项的checked状态发生变化、且它带有子任务其最后一个子节点是TaskList时调用 utils.ts 中的toggleChildren递归地把所有后代条目的checked改为一致Case 2子级驱动当勾选的是没有子任务的叶子条目时插件用一个while循环从当前条目自底向上回溯只要某个父条目的所有直接子条目都被勾选areAllChecked见 task-list.ts就把父条目也置为勾选如果父条目的勾选状态无需改变则立即中断循环。同一插件还会在每次文档变更后通过countCheckedItems重新统计该清单根节点的checked/total并写回stats属性见 utils.ts并用findRootTaskList定位根清单以避免重复统计——这正是进度条与计数保持实时的来源。无限层级子任务Notesnook 允许在单个任务条目下嵌套无限层级的子任务。创建方式如下桌面端 / Web将光标移动到父任务条目的末尾按Enter新建一个任务条目按Tab将其缩进为子任务。移动端将光标移动到父任务条目的末尾按Enter新建一个任务条目点按工具栏中的 Indent缩进按钮将其缩进为子任务。子任务还支持以下特性勾选父任务会自动勾选所有子任务反之亦然即上一节的联动机制可应用于任意层级可以同时选中多个子任务一起标记为已完成/未完成。从源码看无限层级的实现在于任务条目本身允许嵌套子清单TaskItemNode.configure({ nested: true })的配置在测试 task-item.test.ts 中也有体现。嵌套清单不会渲染重复的清单头与工具栏确保深层嵌套时界面依然干净。将已完成任务排序到底部当清单中的条目较多时可以用清单头右侧的排序已完成任务按钮一键把已完成的条目沉到列表底部未完成的保持在上方方便你聚焦剩余工作。该操作底层调用 utils.ts 中的sortList它会先收集当前清单及其所有嵌套子清单descendants中所有TaskList节点嵌套的按逆序处理对每个清单按checked值0 未完成 / 1 已完成做稳定排序即未完成项在前、已完成项在后如果清单中所有条目都已勾选或都未勾选则跳过该清单无排序必要排序完成后会用TextSelection恢复光标原位置避免光标跳动。一键清空已完成任务清单头右侧的清除已完成任务按钮可以一次移除清单中所有已完成的条目常用于清单收尾阶段——把已完成项全部删掉只保留还没做完的事情。底层实现是 utils.ts 中的deleteCheckedItems同样先收集根清单与所有嵌套子清单嵌套的逆序处理确保深层结构先被处理外层映射位置正确对每个清单仅保留attrs.checked为false的子节点用tr.replaceWith替换整个子列表如果所有条目都是未完成状态则跳过不做任何修改。用拖拽手柄重排任务你可以通过每个任务条目行首的拖拽手柄drag handle拖拽任务项改变其在清单内的顺序也可以把条目拖到其他层级。悬停条目时手柄会自动显现源码中由:hover控制.dragHandle的透明度见 component.tsx手柄本体的渲染在 task-item/component.tsx。拖放有一个专门的细节优化默认的 Tiptap 拖放行为在把条目拖到清单末尾时容易溢出生成一个新列表。为此 task-list.ts 注册了一个task-item-drop-override插件覆写handleDrop当被拖放的内容是任务条目、且落点恰好位于某个一级任务清单的末尾时它会改用tr.replaceRangeWith把条目精确插入到该清单的最后位置而不是新建清单让拖到末尾继续追加这个直觉操作符合预期。将任务清单设为只读清单定稿后可以用清单头中的只读按钮{{readonlyTaskList}}把它锁定防止误编辑。这对那些只需照着执行、不需要改动的清单特别有用例如打包清单packing list或发布检查清单release checklist。该设置会同时作用于清单内嵌套的所有子清单再次点击同一按钮即可解除锁定。只读状态在实现上非常彻底清单节点携带readonly属性见 task-list.ts点击只读按钮时代码不仅改写当前清单还会遍历其所有后代TaskList节点一并改写见 component.tsx这正是嵌套清单同样生效的由来只读后清单正文的contentEditable变为falsecontentEditable{editor.isEditable !readonly}粘贴操作也会被preventDefault()拦截见 component.tsx标题输入框在只读时同样变为readOnly无法修改见 component.tsx。相关文档与深入阅读编辑器工具栏 —— Insert 菜单所在的位置以及如何自定义工具栏大纲列表Outline lists —— 用于组织长笔记的可折叠嵌套列表Markdown 快捷输入 —— 用输入[]代替点击菜单提醒Reminders —— 在指定时间收到笔记提醒计划与限制Plans limits —— Essential 计划解锁的能力范围想深入代码可阅读 任务清单扩展源码、清单 UI 组件 与 清单工具函数以及对应的测试用例 task-item.test.ts。赞分享前端移动开发桌面应用应用安全【免费下载链接】notesnookA fully open source end-to-end encrypted note taking alternative to Evernote.项目地址https://gitcode.com/gh_mirrors/no/notesnook点击查看免费下载相关推荐Kimi CLI 的 SetTodoList 工具任务清单驱动的多子任务进度追踪机制Kimi CLI 的 SetTodoList 工具任务清单驱动的多子任务进度追踪机制 导读 SetTodoList 是 Kimi CLI 内置的唯一任务清单人工智能AI Agent代码智能体交互助手CLI工具调用Electron Task 对象参考构建 Windows 任务栏 Jump List 任务的完整指南Electron Task 对象参考构建 Windows 任务栏 Jump List 任务的完整指南 本文以 Electron 官方 API 结构文档中的 T桌面应用跨平台前端Kilo Code Task Todo List 完全指南AI 驱动的任务清单如何跟踪复杂开发工作Kilo Code Task Todo List 完全指南AI 驱动的任务清单如何跟踪复杂开发工作 Task Todo List任务待办清单是 Kilo人工智能大模型AI Agent代码智能体工具调用交互助手CLI上一篇Circuit多数据中心部署实现跨地域云应用编排下一篇如何使用React Native Elements构建专业工业监控界面完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考