5个JavaScript代码片段:解锁SiYuan笔记的隐藏自定义能力
你是否还在为笔记软件不够灵活而烦恼?SiYuan作为一款注重隐私的开源知识管理工具,提供了强大的JavaScript代码片段功能,让普通用户也能通过简单代码实现高级自定义。本文将通过5个实用案例,带你掌握从基础配置到高级交互的完整自定义流程,无需专业开发经验也能打造专属笔记体验。
代码片段功能基础
SiYuan的代码片段系统允许用户通过JavaScript扩展界面功能和交互逻辑。所有相关配置都集中在app/src/config/util/snippets.ts模块中,该模块负责代码片段的加载、渲染和管理。
代码片段的工作原理很简单:用户编写的JavaScript代码会被注入到应用的HTML头部,从而可以访问和修改SiYuan的内部API。系统会自动处理代码的加载顺序和执行环境,确保自定义功能与核心功能无缝集成。
片段1:自动为标题添加序号
这个代码片段可以为文档中的所有标题自动添加层级序号,帮助你在长文档中保持清晰的结构。实现原理是通过监听文档加载完成事件,然后遍历所有标题元素并添加序号前缀。
// 自动为标题添加序号
document.addEventListener('DOMContentLoaded', function() {
// 获取所有标题元素
const headings = document.querySelectorAll('.protyle-wysiwyg [data-node-id]');
// 定义层级计数器
const levelCounts = [0, 0, 0, 0, 0, 0];
headings.forEach(heading => {
// 获取标题层级
const level = parseInt(heading.tagName.replace('H', ''));
if (isNaN(level) || level < 1 || level > 6) return;
// 更新计数器
for (let i = level; i <= 6; i++) {
levelCounts[i] = 0;
}
levelCounts[level]++;
// 生成序号
let numbering = '';
for (let i = 1; i <= level; i++) {
if (levelCounts[i] > 0) {
numbering += (i > 1 ? '.' : '') + levelCounts[i];
}
}
// 添加序号前缀
const contentElement = heading.querySelector('.protyle-action + div');
if (contentElement && !contentElement.innerHTML.startsWith(numbering + '.')) {
contentElement.innerHTML = numbering + '. ' + contentElement.innerHTML;
}
});
});
使用方法非常简单:在代码片段管理界面点击"添加"按钮,选择JavaScript类型,粘贴上述代码并启用即可。系统会在每次加载文档时自动执行这段代码,为所有标题添加序号。
片段2:实现自定义快捷键
SiYuan虽然内置了丰富的快捷键,但有时我们需要根据个人习惯自定义。下面的代码展示了如何添加一个"复制当前块ID"的自定义快捷键(Alt+Shift+C)。
// 自定义快捷键:复制当前块ID (Alt+Shift+C)
document.addEventListener('keydown', function(e) {
// 检查快捷键组合 (Alt+Shift+C)
if (e.altKey && e.shiftKey && e.code === 'KeyC') {
// 获取当前选中的块
const selectedBlock = document.querySelector('.protyle-wysiwyg [data-node-id].protyle-selected');
if (selectedBlock) {
// 获取块ID
const blockId = selectedBlock.getAttribute('data-node-id');
// 复制到剪贴板
navigator.clipboard.writeText(blockId).then(() => {
// 显示提示
siyuan.notification.showMessage('块ID已复制: ' + blockId);
});
e.preventDefault();
e.stopPropagation();
}
}
});
这段代码通过监听全局键盘事件实现快捷键功能。当检测到Alt+Shift+C组合键时,会查找当前选中的块元素,提取其data-node-id属性值并复制到剪贴板,最后通过SiYuan的notification API显示成功提示。
片段3:自动备份每日笔记
对于重要的每日笔记,自动备份功能可以提供额外保障。这个片段会在每天指定时间自动导出当天的日记笔记,并保存到指定目录。
// 自动备份每日笔记
(function() {
// 配置备份时间 (小时:分钟)
const backupTime = "23:59";
// 目标笔记本路径
const targetNotebook = "/日记";
// 计算当前时间与目标时间的差值
function getDelay() {
const now = new Date();
const [hours, minutes] = backupTime.split(':').map(Number);
const target = new Date(now);
target.setHours(hours, minutes, 0, 0);
if (target <= now) {
target.setDate(target.getDate() + 1);
}
return target - now;
}
// 执行备份
function performBackup() {
// 获取今天的日期字符串 (YYYY-MM-DD)
const today = new Date().toISOString().split('T')[0];
// 调用SiYuan导出API
siyuan.api.exportMd({
path: `${targetNotebook}/${today}`,
mode: "single",
withID: false,
withEmbed: true,
withBacklink: false,
withAttr: false,
fileType: "md"
}).then(() => {
siyuan.notification.showMessage(`每日笔记备份成功: ${today}`);
}).catch(err => {
siyuan.notification.showMessage(`备份失败: ${err.message}`, 5000, "error");
});
// 安排下一次备份
setTimeout(performBackup, getDelay());
}
// 立即安排第一次备份
setTimeout(performBackup, getDelay());
})();
该实现使用了自执行函数模式,避免污染全局命名空间。代码会根据设定的备份时间自动计算下次执行时间,然后通过setTimeout递归调用,实现每日自动备份。备份功能通过调用SiYuan的exportMd API实现,支持自定义笔记本路径和导出选项。
片段4:自定义块引用样式
SiYuan默认的块引用样式比较简单,通过代码片段可以实现更丰富的视觉效果,如不同类型的引用使用不同颜色标识。
// 自定义块引用样式
(function() {
// 创建样式元素
const style = document.createElement('style');
style.textContent = `
/* 重要引用样式 */
.protyle-wysiwyg [data-type="quote"] .p[contenteditable="true"]::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
background-color: #ff4d4f;
border-radius: 2px;
}
/* 提示引用样式 */
.protyle-wysiwyg [data-type="quote"] .p[contenteditable="true"]:has(> span:contains("提示:"))::before {
background-color: #faad14;
}
/* 链接引用样式 */
.protyle-wysiwyg [data-type="quote"] .p[contenteditable="true"]:has(> span:contains("链接:"))::before {
background-color: #1890ff;
}
`;
document.head.appendChild(style);
})();
这个代码片段通过动态创建style元素,为不同类型的块引用添加左侧彩色边框。使用了CSS的:has()伪类选择器,可以根据引用内容中的特定文本(如"提示:"、"链接:")自动应用不同颜色,使文档结构更加清晰。
片段5:实现笔记内容搜索高亮
SiYuan内置搜索功能虽然强大,但有时我们需要在阅读长文档时持续高亮显示某些关键词。这个代码片段实现了一个简单的关键词高亮功能,可以在当前文档中标记指定关键词。
// 笔记内容搜索高亮
(function() {
// 配置需要高亮的关键词列表
const keywords = ["重要", "待办", "注意", "思考"];
// 创建样式
const style = document.createElement('style');
style.textContent = `
.keyword-highlight {
background-color: rgba(255, 251, 0, 0.4);
padding: 0 2px;
border-radius: 2px;
}
`;
document.head.appendChild(style);
// 高亮处理函数
function highlightKeywords() {
// 获取所有可编辑内容区域
const contentAreas = document.querySelectorAll('.protyle-wysiwyg .p[contenteditable="true"]');
contentAreas.forEach(area => {
// 保存当前光标位置
const selection = window.getSelection();
let range = null;
if (selection.rangeCount > 0 && area.contains(selection.focusNode)) {
range = selection.getRangeAt(0);
}
// 处理文本节点
const walker = document.createTreeWalker(area, NodeFilter.SHOW_TEXT, {
acceptNode: node => {
// 排除已经高亮的文本和代码块
if (node.parentElement && (node.parentElement.classList.contains('keyword-highlight') ||
node.parentElement.closest('.code-block') ||
node.parentElement.closest('.language-'))) {
return NodeFilter.FILTER_REJECT;
}
return NodeFilter.FILTER_ACCEPT;
}
});
const textNodes = [];
let currentNode;
while (currentNode = walker.nextNode()) {
textNodes.push(currentNode);
}
// 处理每个文本节点
textNodes.forEach(node => {
let content = node.textContent;
let modified = false;
// 检查每个关键词
keywords.forEach(keyword => {
if (content.includes(keyword)) {
modified = true;
// 使用正则表达式全局匹配关键词
const regex = new RegExp(`(${keyword})`, 'g');
content = content.replace(regex, '<span class="keyword-highlight">$1</span>');
}
});
// 如果内容被修改,替换文本节点为span元素
if (modified) {
const span = document.createElement('span');
span.innerHTML = content;
node.parentNode.replaceChild(span, node);
}
});
// 恢复光标位置
if (range) {
selection.removeAllRanges();
selection.addRange(range);
}
});
}
// 监听文档变化
const observer = new MutationObserver(highlightKeywords);
observer.observe(document.body, {
childList: true,
subtree: true,
characterData: true
});
// 初始加载时执行一次
highlightKeywords();
})();
这个代码片段通过创建一个MutationObserver来监听文档变化,当检测到内容更新时自动扫描文本并高亮预设关键词。使用TreeWalker遍历文本节点,避免处理代码块和已高亮内容,确保高亮功能不会干扰正常编辑。
高级应用:片段管理与共享
随着自定义片段增多,管理变得尤为重要。SiYuan的代码片段系统支持批量导入导出功能,你可以将自己编写的实用片段导出为JSON文件,与其他用户共享。
所有代码片段的管理功能都在app/src/config/util/snippets.ts中实现,包括:
- 片段的增删改查
- 启用/禁用状态管理
- 搜索和过滤功能
- 导入/导出功能
要导出你的代码片段集合,只需在代码片段管理界面点击"导出"按钮,系统会生成一个包含所有片段的JSON文件。导入时选择该文件即可恢复所有自定义片段。
注意事项与最佳实践
在使用JavaScript代码片段时,需要注意以下几点:
- 代码片段会直接影响SiYuan的运行环境,错误的代码可能导致应用不稳定
- 升级SiYuan后,部分内部API可能变化,需要检查自定义片段是否兼容
- 复杂功能建议先在测试环境验证,再应用到生产笔记中
- 定期备份你的代码片段,防止意外丢失
建议将常用的代码片段整理成文档,记录其功能、使用场景和依赖的API版本,以便日后维护和分享。对于特别复杂的功能,可以考虑将其开发为正式插件,获得更好的兼容性和支持。
通过本文介绍的5个实用代码片段,相信你已经掌握了SiYuan自定义功能的基本方法。这些示例仅仅展示了冰山一角,结合SiYuan丰富的内部API,你可以实现更多个性化功能,让笔记系统真正为你所用。
现在就打开SiYuan的代码片段管理界面,开始你的定制之旅吧!如果创建了实用的代码片段,欢迎在社区分享,帮助更多用户解锁SiYuan的隐藏潜力。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考






