三步从零搭建 Zotero Better Notes 智能笔记模板,让文献笔记实现一键自动生成
【免费下载链接】zotero-better-notesEverything about note management. All in Zotero.项目地址: https://gitcode.com/gh_mirrors/zo/zotero-better-notes
凌晨一点,你对着第三篇论文复制标题、粘贴作者、手动对齐引用格式,眼睛快睁不开了——这种机械重复的夜晚,经历过一次就再也不想有第二次。Zotero Better Notes 的笔记模板功能,正是为消灭这类重复劳动而生的:你只需要写一份模板,之后每打开一篇文献,笔记都能按你的框架一键自动成型。
这篇文章会带你从零动手:先认识模板的构成,再做出第一个最小可用的模板,然后一步步给它加装"脚本大脑"、升级成文献专用模板、打通批量处理流程。全程不绕弯子,每个阶段都有能直接抄走的代码。
动手之前:先认识模板这块"积木"的两个零件
在写第一行模板代码前,你只需要记住一件事:任何一个笔记模板都由名称和内容两部分拼成,就像一块积木的两个卡扣。
- 名称:必须以
[类型]开头,例如[Text] 随手记、[Item] 论文精读卡。方括号里的类型决定了模板能被用在什么场景,后面会细讲。 - 内容:主体是 Markdown 或 HTML 排版文本,中间可以混入 JavaScript 脚本来动态生成数据。
模板本身是一段 YAML 文本,既可以在编辑器里手动写,也可以整段分享给别人。如果你之后想深入研究模板引擎的实现,可以翻翻src/modules/template/目录下的api.ts和controller.ts,类型定义在 typings/template.d.ts,完整机制说明在 docs/about-note-template.md。
第一块积木:5 分钟做出你的第一个"当前时间"模板
先别急着写复杂的文献模板,我们从最小可用的例子开始。把下面这段代码完整复制:
name: "[Text] 随手记" content: |- // @use-markdown # 随手记 创建于:${new Date().toLocaleString()}然后按这两步把它装进 Zotero:
- 点击 Zotero 菜单栏的「工具」,选择「从剪贴板新建模板」,粘贴后确认。
- 打开任意一篇笔记,在编辑器工具栏找到"Insert Template to cursor line"(插入模板到光标所在行)按钮,从弹出的列表里选中「随手记」。
你会看到笔记里立刻出现了标题和一行当前时间。别小看这行时间——它其实已经用上了模板的动态脚本能力:${...}里的内容会被当作 JavaScript 执行,执行结果替换回文本里。${{...}}$ 是它的多行版本,里面可以写完整的函数逻辑。也就是说,你在模板里写的不是死文字,而是一段"每次插入都会重新计算"的活代码。
💡 小提醒:如果你在「笔记模板编辑器」里预览,脚本返回时
_env.dryRun会被置为true,此时脚本里不要做任何改动库内容的操作,防止误伤你的文献数据。
第二块积木:给模板装上"会算数的脑袋"
${new Date()}只是开胃菜。真正让模板值钱的是它能读取文献条目字段。继续在「随手记」模板上加代码:
${{ const tagList = topItem.getTags().map(t => t.tag); return tagList.length ? "标签:" + tagList.join("、") : "这篇文献还没有标签"; }}$这里出现了一个新变量topItem,它代表"正在被处理的当前文献条目"。类似的常用字段读取有:
${topItem.getField("title")}—— 标题${topItem.getField("year")}—— 年份${topItem.getField("DOI")}—— DOI 编号${topItem.getCreators().map(au => au.lastName).join("; ")}—— 作者姓氏列表
还可以给脚本套一层try/catch做容错,避免遇到缺字段的文献时整段渲染报错:
${{ try { const t = topItem.getField("title"); return t || "(这篇文献没有标题)"; } catch (e) { return "读取标题时出错"; } }}$这样一来,即使遇到信息残缺的条目,模板也能优雅地给出兜底文案,而不是让笔记生成失败。
第三块积木:把模板升级成"论文精读卡"
现在我们把前面学的东西串起来,做一个真正能用的文献专用模板。它的类型要改成[Item]——这种模板会针对文献条目循环处理,是写文献笔记的主力。
name: "[Item] 论文精读卡" content: |- // @use-markdown // @use-refresh // @author 你的昵称 # ${topItem.getField("title") || "未命名文献"} ## 1. 这篇论文讲了什么 一句话概括: ## 2. 出处速览 | 项目 | 信息 | | --- | --- | | 作者 | ${topItem.getCreators().map(au => [au.firstName, au.lastName].filter(Boolean).join(" ")).join("; ") || "佚名"} | | 年份 | ${topItem.getField("year") || "不详"} | | 期刊/会议 | ${topItem.getField("publicationTitle") || topItem.getField("conferenceName") || "未收录"} | | DOI | ${topItem.getField("DOI") ? `[${topItem.getField("DOI")}](https://doi.org/${topItem.getField("DOI")})` : "无"} | ## 3. 核心结论 - - ## 4. 值得质疑与跟进的点 - [ ] - [ ]创建好之后,选中一篇文献,用同一枚"插入模板"按钮把它插入——你会看到标题、作者、年份、期刊、DOI 全部自动填好,连 DOI 都直接变成了可点击的链接,剩下的只是你动脑写结论。整个流程从手动复制粘贴的十几分钟,压缩到了几秒钟。
这个模板开头的// @use-refresh也很关键:它允许你之后用「从模板更新内容」重新刷新生成的部分。比如你修改了文献元数据,一键更新就能把旧信息全部对齐,不用再删了重做。
让模板更进一步:三阶段流水线与数据共享
如果只是单篇生成,[Item]模板已经够用。但当你同时选中十篇文献、想要一份统一格式的批量笔记时,就该认识模板的三阶段结构了。用// @阶段名-begin和// @阶段名-end把内容圈起来,就能让不同段落分别在不同时机执行:
| 阶段 | 执行时机 | 典型用途 |
|---|---|---|
| beforeloop | 循环开始前,只跑一次 | 写总标题、初始化统计变量 |
| default | 对每篇文献各跑一次 | 生成每篇的核心内容 |
| afterloop | 循环结束后,只跑一次 | 写总结、汇总统计结果 |
下面这段演示了三个阶段配合sharedObj共享数据完成标签统计:
// @beforeloop-begin ${{ sharedObj.tags = new Set(); return "开始批量生成文献笔记"; }}$ // @beforeloop-end // @default-begin ## ${topItem.getField("title") || "未命名文献"} ${{ topItem.getTags().forEach(t => sharedObj.tags.add(t.tag)); return ""; }}$ // @default-end // @afterloop-begin ${{ return "本次共涉及标签:" + [...sharedObj.tags].join("、"); }}$ // @afterloop-endsharedObj是贯穿三个阶段的公共储物柜,beforeloop 阶段算好的东西,后面的阶段都能取用。这样你就不用在每篇文献上重复计算相同的数据,批量处理的性能也更好。
背后的机关:那些以 // @ 开头的"特殊指令"
你在模板里会看到很多以// @开头的注释行,它们不是普通注释,而是控制模板行为的开关,渲染时会被悄悄吃掉、不显示在笔记里。常见的有这些:
| 指令 | 作用 | 注意点 |
|---|---|---|
// @use-markdown | 声明按 Markdown 语法渲染 | 不写的话,模板会被当 HTML 处理 |
// @use-refresh | 允许生成结果被"从模板更新"刷新 | 启用后正文里不能再出现---分隔线,否则会干扰更新标记 |
// @author 你的名字 | 标注模板作者 | 分享模板时的署名 |
// @link 来源地址 | 标注模板发布来源 | 方便别人反馈问题 |
// @beforeloop-begin/end | 圈定某阶段的代码范围 | 只有 Item 模板支持多阶段 |
有个细节值得注意:特殊指令必须单独成行,不能藏在代码块里,否则系统只会把它当作普通注释,你的开关就失效了。
三种模板类型怎么选:别再纠结了
打开模板编辑器你会发现,模板类型远不止上面两种。快速对照这张表就能选对:
| 类型 | 适用场景 | 主要全局变量 |
|---|---|---|
[Item] | 针对一篇或多篇文献条目批量生成 | topItem、items、sharedObj、targetNoteItem |
[Text] | 不绑定文献的通用文本,如读书笔记、会议记录 | targetNoteItem、sharedObj |
| 内置模板 | 系统功能,如QuickInsert笔记链接、QuickNote注释转笔记、ExportMDFileName导出文件名 | link、noteItem、annotationItem 等 |
内置模板的名字是系统锁定的,不能改名。当项目有破坏性更新时,旧模板会被保留并升级为V2、V3这样的新版本,保证你已有的笔记不受影响。
避坑日记:新手最容易踩的 4 个坑
我自己刚接触模板时,以下四个坑基本都踩过一遍,写出来帮你省掉这些冤枉路:
| 症状 | 真实原因 | 解决办法 |
|---|---|---|
| 导入后模板列表里找不到 | YAML 格式不对,name或content字段不完整 | 检查缩进和字段名,重新复制导入 |
| 脚本原样输出、完全不执行 | JavaScript 语法错误 | 打开 Zotero 调试控制台看报错,定位到具体行 |
| 点「从模板更新」后内容纹丝不动 | 模板开头漏了// @use-refresh | 补上这个指令再重新生成一次 |
| 特殊符号显示成乱码 | 在 Markdown 语法里出现了冲突字符 | 改用 HTML 实体或转义字符 |
另外提醒一句:// @use-refresh和正文分隔线是"水火不容"的,如果你既想支持刷新,又想在模板里画一条---分割线,二选一吧,别硬凑。
把你的模板分享出去,也去社区"进货"
写好一份顺手的模板后,分享给别人其实非常轻松:打开「笔记模板编辑器」,选中要分享的模板,点击「选项」→「复制分享代码」,系统会把它打包成标准的 YAML 分享格式:
name: "[Item] 论文精读卡" content: |- // @author 你的昵称 // @link 发布页地址 模板正文……拿到别人分享的代码后,用回文章开头那招——「工具」→「从剪贴板新建模板」——一键导入就能用。社区里已经积累了大量现成模板,与其从零憋一份,不如先"进货"再改造,效率翻倍。
现在,就从这三个动作开始
到这里,模板的完整链路你已经摸清了。别急着追求一步到位,按下面的顺序动手:
- 导入一个「当前时间」模板,跑通导入和插入的完整流程,找到手感;
- 改造一份现成模板,把
topItem.getField(...)换成你真正常用的字段,加入自己的章节结构; - 造你的第一份
[Item]模板,解决你最痛的那个场景——可能是文献速读卡,也可能是周报汇总。
最后送你一句话:模板的厉害之处从来不在代码有多花哨,而在于它能不能让明天的你少熬一次夜。先解决一个小痛点,剩下的交给时间。
【免费下载链接】zotero-better-notesEverything about note management. All in Zotero.项目地址: https://gitcode.com/gh_mirrors/zo/zotero-better-notes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考