系列第十四篇前文:Obsidian 模板系统:从零到一构建知识生产线下一篇:10 个必装插件及协同用法
上一篇讲完 Templater 语法,我猜你干了一件事:打开插件,照着示例敲了几个模板,跑通了,然后……没有然后了。
模板躺在 Templates 文件夹里吃灰。因为光有语法,你不知道该拿它做什么。就像给你一把好刀,但你没想好切什么菜。
这篇就不讲语法了。直接给你三套我用了半年、反复改过的成品模板,覆盖三个最高频的场景:读书、开会、管项目。
先说个原则,免得你用歪了:模板不是填空题,是思维脚手架。
填空题是"把空填满就行",脚手架是"逼你按正确顺序思考"。好的模板,能强制你规范输入,把"随手记"变成"标准化生产"。你慢慢会体会到,这俩差别有多大。
场景一:读书笔记模板(知识内化引擎)
先说你最可能遇到的痛点。
以前我记读书笔记是这样的:读的时候划重点,读完打开一个空白笔记,凭记忆把划线内容抄一遍,抄完自我感动,然后再也不看。说白了就是个摘抄本,抄完就锁进柜子里。
还有个更烦的事:笔记开头那几行 YAML,书名、作者、日期,每次手敲,每次格式都不一样。有的用冒号,有的用引号,时间长了 Dataview 根本查不了。
这个模板把两个问题一起解决:创建时问你几个问题,答案自动生成标准 Frontmatter;正文里强制你先写思考,再摘抄。
模板代码:TPL_读书笔记.md
<%*// ===== 交互区:新建笔记时,Templater 会依次问你几个问题 =====const bookName = (await tp.system.prompt("书名", "例如:卡片笔记写作法"))?.replace(/"/g, "“") || "未命名";const author = (await tp.system.prompt("作者", "未知")) || "未知";const year = (await tp.system.prompt("出版年份", "例如 2023")) || "未知";const status = await tp.system.suggester(["未读", "在读", "读完"], ["未读", "在读", "读完"]);const bookType = await tp.system.suggester(["技术", "人文", "商业", "其他"], ["技术", "人文", "商业", "其他"]);%>---type: bookbook_name: "<%= bookName %>"author: "<%= author %>"publish_year: "<%= year %>"status: <%= status %>book_type: <%= bookType %>tags: [读书笔记, <%= bookType %>]created: <% tp.date.now("YYYY-MM-DD") %>---# 📖 <% tp.file.title %>> <%= bookName %> · <%= author %> · <%= year %> · <%= status %>## 核心观点<% tp.file.cursor() %>## 与我何干> 这本书跟你有什么关系?想到了什么先写下来,别管对不对。## 摘录> ## 行动清单- [ ] 三个设计点,逐个说
第一,交互式元数据捕获。 新建笔记的瞬间,Templater 弹五个问题:书名、作者、出版年、阅读状态、书籍类型。你答完,Frontmatter 自动生成,格式永远是统一的。不用记 YAML 语法,不用对齐冒号。
第二,光标强制落位。 注意 tp.file.cursor() 这一行。创建完成后,光标自动停在"核心观点"下面。你打开笔记就是写,不用滚动,不用找位置。而区块顺序是刻意的:核心观点 → 与我何干 → 摘录 → 行动清单。
先思考,再摘录,最后定行动。这个顺序本身就是脚手架。摘抄是最后一步,因为摘抄最爽,最容易骗自己"我在学习"。
第三,标签跟着类型走。 你选了"技术",tags 里自动带上"技术"。以后想找"我看过哪些技术书",一个 Dataview 查询就出来了,不用手动打标签。
避坑:书名里有冒号怎么办
你肯定遇到过:书名《卡片笔记:写作法》,手敲 YAML 时冒号后面没加引号,整个 Frontmatter 崩了,后面全是红色报错。
这个模板已经处理了。看第一行:.replace(/"/g, "“") 会把书名里的英文双引号替换成中文引号,再用双引号把整个值包起来。冒号在引号内是合法的,不会崩。这招对会议记录、项目名称同样有效。
坑位提醒: 如果你的 Templater 版本比较老(1.16 之前),tp.system.suggester 可能没有"取消返回 null"的行为,弹窗别乱点 Esc,会中断生成。升级插件就行。
场景二:会议记录模板(信息流转枢纽)
第二个高频场景:开会。
开会的痛不用我多说吧。开完会,记录写了一整页,全是"张总说……李总认为……",看着很充实,实际上要找人、要跟进度的时候,啥也查不到。关键决议淹没在流水账里,待办事项开完会就忘。
这个模板的思路反着来:开会前就定好结构,记录只填结论和待办,不记流水账。
模板代码:TPL_会议记录.md
<%*// ===== 交互区 =====const dateStr = tp.date.now("YYYY-MM-DD dddd", 0, "zh-cn");// 参会人名单:人少直接改这个数组;人多了建议挪到 Lists/People.md 统一维护(见文末进阶)const people = ["张三", "李四", "王五", "赵六"];const attendees = (await tp.system.suggester(people, people, true, "选参会人(可多选)", true)) || [];const projectName = (await tp.system.prompt("关联项目(没有就回车跳过)", "")) || "";const hasAction = await tp.system.suggester(["有明确待办", "暂无待办"], [true, false]);%>---type: meetingdate: "<%= dateStr %>"attendees: [<%= attendees.map(p => `"${p}"`).join(", ") %>]project: "<%= projectName %>"tags: [会议记录, meeting]---# 📋 会议记录:<% tp.file.title %>- **日期**:<%= dateStr %>- **参会人**:<%= attendees.map(p => `[[${p}]]`).join("、") %>- **关联项目**:<%= projectName ? `[[${projectName}]]` : "无" %>## 议题> 只记结论和分歧点,讨论过程一句话带过。别当速记员。## 决议-<%* if (hasAction) { %>## 📌 待办事项 #meeting-action- [ ] 事项 / 负责人: / 截止:- [ ] 事项 / 负责人: / 截止:<%* } else { %>## 待办事项- 暂无<%* } %>三个设计点,逐个说
第一,日期星期自动填,参会人自动双链。 日期那行 tp.date.now("YYYY-MM-DD dddd", 0, "zh-cn"),自动生成"2026-08-07 星期五"这种格式。参会人用 tp.system.suggester 多选,选完自动变成 [[张三]]、[[李四]] 这种双链。Vault 里每个人名就是一张名片,点进去能看这个人参与过哪些会议。
多选的秘密在最后一个参数:tp.system.suggester(选项, 选项, true, "提示语", true),第 5 个参数 allow_multiple_selection 设为 true,就能多选了,返回的是一个数组。
第二,决议和待办强制分离。 创建时会问"有明确待办吗?"。选"有",自动生成带 - [ ] 的待办区块,标题上挂 #meeting-action 标签;选"没有",只留一个"暂无"。这个标签是给 Dataview 用的,看下一节。
会后追踪不用翻聊天记录。建一个查询笔记,贴这个:
```dataviewTASKFROM #meeting-actionWHERE !completed```所有会议里没勾完的待办,自动汇总成一张清单。谁的事没办,一目了然。这条查询比任何"会议纪要同步群"都靠谱。
第三,关联项目防重复。 创建时输入项目名,模板会自动拼成 [[项目名]] 双链。Vault 里已有同名项目笔记,直接连上;没有,就是一个红链,点一下创建,顺手的事。不会出现"这个项目我建过两个笔记"的惨案。
避坑:参会人名单别写死在模板里
模板里那个 people 数组,人一多就不好维护了。改名单得动模板,模板一乱全完。
正确的做法:把名单挪到独立笔记,比如 Lists/People.md,每行一个人名。模板里用 tp.file.include 把名单嵌进来:
<%*// 从 Lists/People.md 读取名单,改名单不用动模板const people = (await tp.file.include("[[Lists/People.md]]")) .split("\n").map(s => s.trim()).filter(Boolean);%>Lists/People.md 长这样:
张三李四王五赵六以后加人、减人,只改这一个文件,模板代码一行不动。
场景三:轻量级项目管理模板(进度可视化看板)
第三个场景:管项目。
Obsidian 原生没有看板视图,这是公认的短板。装个 Kanban 插件吧,一个小项目不值当;用文件夹管理吧,十几个文件堆一起,进度全靠脑补。
我的答案是:不装重型插件,用 Frontmatter 当数据源,用 Dataview 当看板。 轻,快,还能跟其他笔记联动。
模板代码:TPL_项目.md
<%*// ===== 交互区 =====const status = await tp.system.suggester(["规划中", "进行中", "已完成"], ["规划中", "进行中", "已完成"]);const priority = await tp.system.suggester(["高", "中", "低"], ["高", "中", "低"]);// 截止日期默认 30 天后,格式固定 YYYY-MM-DD,别手输别的格式const deadline = (await tp.system.prompt("截止日期(YYYY-MM-DD)", tp.date.now("YYYY-MM-DD", 30))) || tp.date.now("YYYY-MM-DD", 30);let milestoneCount = parseInt(await tp.system.prompt("几个里程碑?最多 10 个", "3"), 10);if (isNaN(milestoneCount)) milestoneCount = 3;milestoneCount = Math.min(Math.max(milestoneCount, 1), 10);%>---type: projectstatus: <%= status %>priority: <%= priority %>deadline: "<%= deadline %>"milestones: <%= milestoneCount %>tags: [项目]---# 🚀 <% tp.file.title %>## 🎯 目标> 这个项目要交付什么?一句话说清。## 🗺️ 里程碑<%* for (let i = 1; i <= milestoneCount; i++) { %>- [ ] 里程碑<%= i %>:<%= i === 1 ? "先写第一步" : "" %><%* } %>## 本周进展> 每周往里填几行,周报直接引用这一节,不用再写一遍。## 风险与阻塞-## 📎 复盘> 项目结束后写:做对了什么、翻车在哪、下次怎么改。三个设计点,逐个说
第一,状态驱动结构。 Frontmatter 里 status、deadline、priority 三个字段,就是未来看板的数据源。所有项目笔记统一这套字段,Dataview 就能把它们汇总成一张表:
```dataviewTABLE status, priority, deadlineFROM #项目SORT deadline ASC```所有项目按截止日期排好,谁快到期了、谁卡在"进行中"超过一周了,扫一眼就知道。这就是最轻的看板——不用插件,一个查询块搞定。以后要是真上了 Kanban 插件,这套 Frontmatter 直接就能映射过去,不浪费。
第二,里程碑自动生成。 创建时问你"几个里程碑",你填 5,模板就用 JavaScript 循环生成 5 个 - [ ] 里程碑N: 任务。注意两处保护:parseInt 把输入转成数字,输入"abc"也不崩;Math.min(Math.max(n, 1), 10) 把数量钳制在 1 到 10 之间。填 99 也只会生成 10 个。
这个上限不是随便定的。之前我填过 20 个里程碑,生成那一下 Obsidian 明显卡顿,而且 20 个空任务没人会认真勾。模板是帮你干活,不是给你堆工作量。
第三,周报引用区。## 本周进展 这个区块是预留的钩子。Daily Note 模板里写一行:
## 项目速览![[项目名#本周进展]]打开今天的日记,所有在跟项目的进展自动嵌入进来。周报不用重新写,把日记里这块复制出去就完事。
避坑:deadline 格式是硬约束
deadline 字段必须严格 YYYY-MM-DD,比如 2026-09-01。写成"9月1号"、"2026/09/01"、"",Dataview 全部认不出来,排序直接乱掉,看板瞬间变废板。
所以模板里 prompt 的默认值直接给了 tp.date.now("YYYY-MM-DD", 30)——30 天后的标准日期,你只需要改数字,不需要记格式。
通用注意事项:四条铁律
三个模板讲完,说几条所有模板通用的规矩。这几条是我踩坑踩出来的。
一、模板放哪,怎么命名。 所有模板放进 Templater 设置里指定的文件夹(我的是 90-Templates/)。文件名加 TPL_ 前缀,比如 TPL_读书笔记.md。这样普通笔记和模板一眼分开,也不会被搜索的时候误当成内容。
二、JavaScript 安全边界。 模板里禁止写 require('fs') 这类高危系统调用——恶意模板能直接读写你硬盘上的任何文件。Templater 默认也拦着,但别去开那个口子。真要调外部 API(比如按 ISBN 查书籍信息),把逻辑封装成独立的用户脚本(User Scripts),模板里只留一行调用。
三、版本管理。 模板文件夹纳入 Git 管理(Obsidian Git 插件就行)。每次大改之前提交一次。模板语法写错了,批量创建笔记失败,Git 回滚,一分钟恢复。没有版本管理的模板,改坏了只能哭。
四、渐进式定制。 新模板先原封不动用 1-2 周,把实际痛点记下来,再动手改。千万别第一天就叠加一堆交互逻辑——"这个加个弹窗,那个加个判断",改完模板比你写的内容还长,最后连你自己都不想用。某个功能一周用不到一次,就删掉。
故障排查速查表
模板不生效,先别怀疑模板,按这个表查:
<% %> 没执行 | ||
.replace() 转义,值加双引号包裹 | ||
[[双链]] | ||
#meeting-action | ||
YYYY-MM-DD,用 tp.date.now 生成 | ||
allow_multiple_selection 参数 |
手动记录 vs 模板生成
空口无凭,上数据。这是我实际用下来的一笔账:
本周进展 区块 |
三分钟到三十秒,差的不是两分半,是"记笔记的意愿"。意愿这东西,一打折,笔记就断了。
收个尾
三套模板,覆盖的是个人知识管理最核心的闭环:读书是输入,会议是处理,项目是输出。
它们不是终点。模板这东西,永远没有"完美版本",只有"够用版本"。先用起来,用出问题,再改。
遇到报错,优先回上一篇把配置清单过一遍,别一上来就怀疑模板本身。语法、权限、路径,90% 的问题出在这三样。
下一篇进入插件阶段。模板有了,数据也沉淀了,接下来教你怎么用 Dataview、Kanban、QuickAdd 把这些静态笔记激活——让知识库从"存东西的地方"变成"会自己跑的东西"。
到时候见。
系列目录
第 1 篇 · Obsidian 系统安装与知识库配置(已发布 ✅)第 2 篇 · Markdown 语法全解析(已发布 ✅)第 3 篇 · 双向链接(已发布 ✅)第 4 篇 · 笔记命名规则与文件夹结构(已发布 ✅)第 5 篇 · 标签系统入门(已发布 ✅)第 6 篇 · 基础工作流(已发布 ✅)第 7 篇 · Canvas / Excalidraw / Mermaid 可视化入门(已发布 ✅)第 8 篇 · 搜索与命令面板(已发布 ✅)第 9 篇 · OpenClaw + Obsidian 实战(已发布 ✅)第 10 篇 · Hermes Agent + Obsidian 实战(已发布 ✅)第 11 篇 · Claude Code / Codex 实战(已发布 ✅)第 12 篇 · WorkBuddy + Obsidian 实战(已发布 ✅)第 13 篇 · Obsidian 模板系统(已发布 ✅)第 14 篇 · 三种核心场景模板实战(本文)第 15 篇 · 10 个必装插件及协同用法(待发布)
📎 关联笔记
• [[100-笔记/第 13 篇 · Obsidian 模板系统:从零到一构建知识生产线]] • [[100-笔记/Obsidian技能体系总览]] • [[90-Templates/索引]]
夜雨聆风