遇到的问题
我使用了插件Template
创建了简单的模板,如下
---
title: "<% tp.file.title %>"
date: "<% tp.date.now("YYYY-MM-DD HH:mm") %>"
author: Rekutosei
tags:
---
# "<% tp.file.title %>"
但是目前我使用Ob新建笔记时
它默认帮我使用了“未命名”、“未命名1”、“未命名2”这些笔记名
导致title属性值派不上用场。
后来我看到网友的图:
Ta在新建笔记时,Ob会先要求输入笔记名称。
这与我的需求刚好符合,但是我不知道如何设置才能做到像Ta这样
谢谢你。
这个插件我尝试过了,不是很方便,它需要创建笔记文件后,再使用命令执行这个插件来统一“文件名、title属性、一级标题”
不过就在刚才我找到解决办法了
在CSDN找到的攻略
但是这篇文章被锁VIP了,游客看不了
大致原理还是利用Template插件,在模板开头插入一段JS
提示用户输入一个文件名,并将当前文件重命名为用户输入的名字
---
<%* const newFileName = await tp.system.prompt("Enter a name for this file:"); if (newFileName) { await tp.file.rename(newFileName); } %>
title: "<% newFileName %>"
date: "<% tp.date.now("YYYY-MM-DD HH:mm") %>"
author: Rekutosei
tags:
---
# <% newFileName %>
lspzc
4
我写了一个,你可以看一下,可能有些个性化的文字需要改一下
lspzc
6
---
<%*
/* ========== 配置区 - 可扩展的常量配置 ========== */
const CONFIG = {
AUTHOR: "lspzc",
BASE_FOLDER: "/md",
EXCLUDE_FOLDERS: new Set(["papers", "attachments"]),
FILE_EXT: ".md"
};
/* ========== 核心功能函数 ========== */
/* 获取分层文件夹 */
async function getHierarchicalFolders() {
let currentPath = CONFIG.BASE_FOLDER;
let finalPath = "";
while (true) {
const { folders } = await app.vault.adapter.list(currentPath);
const validFolders = folders
.map(fullPath => fullPath.split("/").pop())
.filter(folder => !CONFIG.EXCLUDE_FOLDERS.has(folder.toLowerCase()));
const options = [];
if (currentPath !== CONFIG.BASE_FOLDER) options.push("🔙");
options.push(...validFolders, "✔️");
const chosen = await tp.system.suggester(
options,
options,
false,
`选择目录 📁 当前路径: ${currentPath.replace(CONFIG.BASE_FOLDER, "根目录")}`
);
if (!chosen) return null;
if (chosen === "✔️") {
finalPath = currentPath.replace(CONFIG.BASE_FOLDER + "/", "");
break;
} else if (chosen === "🔙") {
currentPath = currentPath.split("/").slice(0, -1).join("/");
} else {
currentPath = `${currentPath}/${chosen}`;
}
}
return finalPath;
}
/* 判读文件是否存在 */
async function isFileExists(folderPath, fileName) {
const fullPath = `${CONFIG.BASE_FOLDER}/${folderPath}/${fileName}${CONFIG.FILE_EXT}`.replace(/\/+/g, "/");
return await app.vault.adapter.exists(fullPath);
}
/* 获取唯一文件名 */
async function getUniqueFileName(chosenFolder) {
while (true) {
const titleName = await tp.system.prompt("请输入笔记标题 ✏️", "未命名笔记");
if (!titleName) return false;
if (!(await isFileExists(chosenFolder, titleName))) return titleName;
new Notice(`⚠️ "${titleName}" 已存在,请换用其他名称`);
}
}
/* 新增文件夹流程 */
async function createNewFolder() {
const basePath = await getHierarchicalFolders();
if (!basePath) return null;
while (true) {
const folderName = await tp.system.prompt("请输入新文件夹名称 📁", "新文件夹");
if (!folderName) return null;
const fullPath = `${CONFIG.BASE_FOLDER}/${basePath}/${folderName}`.replace(/\/+/g, "/");
if (!(await app.vault.adapter.exists(fullPath))) {
await app.vault.createFolder(fullPath);
return `${basePath}/${folderName}`;
}
new Notice(`⚠️ 文件夹 "${folderName}" 已存在,请换用其他名称`);
}
}
/* 主流程 */
try {
// 判断使用现有目录还是新建目录
let isNewFolder;
try {
isNewFolder = await tp.system.suggester(
["使用现有目录", "创建新文件夹"],
[false, true],
true,
"选择文件夹操作 🗃️"
);
} catch (error) {
new Notice("🛑 操作已取消");
return;
}
// 获取新建笔记的路径
let chosenFolder;
if (isNewFolder) {
// 新建目录,调用新建目录方法
chosenFolder = await createNewFolder();
} else {
// 选择原有目录,调用获取分层文件夹方法
chosenFolder = await getHierarchicalFolders();
}
if (!chosenFolder) {
new Notice("🛑 操作已取消");
return;
}
// 获取唯一笔记标题
const titleName = await getUniqueFileName(chosenFolder);
if (!titleName) {
new Notice("🛑 操作已取消");
return;
}
// 获取笔记属性
try {
// 收集Frontmatter
// 笔记状态,如果用户取消输入则退出
const state = await tp.system.suggester(
["进行中","待办/未开始","持续更新","已完成"],
["doing","todo","update","done"],
true,
"选择笔记状态 🔄"
);
// 是否添加标题序号,如果用户取消输入则退出
const isAdd = await tp.system.suggester(
["添加标题编号", "不添加编号"],
[true, false],
true,
"标题编号设置 🔢"
);
// 构建 Frontmatter
tp.frontmatter = {
author: CONFIG.AUTHOR,
tags: "",
state,
...(isAdd && { "number headings": "auto, first-level 1, max 6, _.1.1" })
};
} catch (error) {
new Notice("🛑 操作已取消");
return;
}
// 移动文件
await tp.file.move(`${CONFIG.BASE_FOLDER}/${chosenFolder}/${titleName}`);
} catch (error) {
new Notice(`❌ 操作异常: ${error.message}`);
}
-%>
author: <% tp.frontmatter.author %>
tags: <% tp.frontmatter.tags %>
state: <% tp.frontmatter.state %>
<%* if (tp.frontmatter["number headings"]) { -%>
number headings: <% tp.frontmatter["number headings"] %>
<%* } -%>
---
<% tp.file.cursor() %>
1 个赞
感谢你提供如此完整的解决方案 
你的方案确实非常强大,功能很丰富,比如路径选择、唯一性检查等等,还有很强的可配置性,看得出来是下了很大功夫的。
不过对于我这种刚接触 Template 插件的新手来说,理解起来还是有点挑战 
我觉得可以把两种方式结合起来:日常记录用我上面提到的简单版提高效率,正式写文档时用你的高级流程来规范管理。
再次感谢你的贡献!