-
希望优化下思源网页端的 url 路径的细节
2025-07-21 02:13拿走不谢
// 自动给浏览器URL添加当前文档ID (()=>{ if(!isBrowser()) return; const main = (event) => { const id = event?.detail?.protyle?.block?.id; setUrlParam('id', id); }; eventBusOn('loaded-protyle-static', main); eventBusOn('switch-protyle', main); function eventBusOn(eventName, callback) { const pluginName = 'my-custom-plugin'; if(window.siyuan.ws.app.plugins?.length === 0) { console.log('绑定事件'+eventName+'失败,请至少安装一个插件'); return false; } let myPlugin = window.siyuan.ws.app.plugins.find(item=>item.name === pluginName); if(!myPlugin) { const Plguin = Object.getPrototypeOf(window.siyuan.ws.app.plugins[0].constructor); const MyPlugin = class extends Plguin{}; myPlugin = new MyPlugin({app:window.siyuan.ws.app.appId, name:pluginName, displayName:pluginName}); myPlugin.openSetting = null; // 防止顶部插件按钮添加设置菜单 window.siyuan.ws.app.plugins.push(myPlugin); } myPlugin.eventBus.on(eventName, callback); return true; } function setUrlParam(key, value) { const url = new URL(window.location.href); url.searchParams.set(key, value); window.history.pushState({}, '', url.toString()); } function isBrowser() { return !navigator.userAgent.startsWith("SiYuan") || navigator.userAgent.indexOf("iPad") > -1 || (/Android/.test(navigator.userAgent) && !/(?:Mobile)/.test(navigator.userAgent)); } })();
-
社区|已完成思源官方用户指南的迁移
2025-07-20 15:09意思相近,但不够清晰,你找下这个,看能一下子找到吗?https://docs.siyuan-note.club/zh-Hans/reference/database/table.html 但 https://docs.siyuan-note.club/zh-Hans/ 这个网站可以,很清晰。
我怕直接调整后你不同意,如果没意见后面空了调整下结构,看起来更清晰明了些。不过,可能有些调整我没有权限,还得你来。
还是一下子调整好更好,后面内容多了,调整起来更麻烦。
结构清晰,用户知道内容往哪放,否则用户可能会按自己的想法放,时间久了就很混乱。
更新:
简单调整了下感觉清晰多了,主要把开发者指南和高级自定义分割开来,把之前开发需要的内容移动到开发者指南里。不要散落到各处。
高级自定义如果用户需要可以放到深入了解里,不然会把开发者文档和其他文档杂糅在一起,不方便查询。
开发者文档更像一个手册随时查询,不应该有无关内容影响。
-
社区|已完成思源官方用户指南的迁移
2025-07-20 14:32大佬,最近使用 https://www.siyuan-note.club/ 一段时间后发现,这个网站的结构混乱,每次想找东西都要点半天。
我觉得,整体结构应该这样划分更清晰:
- 基础教程(可包括官方教程)
- 进阶教程
- 社区资源(包括用户分享教程或资源等,与 1 和 2 的不同是,1 和 2 是偏教程类,社区资源更自由,随意分享)
- 开发者教程(包括插件开发,主题开发,数据字段介绍,api 等)
- api(也可放到 4 开发者教程中)
- 其他
-
[js] 不用插件:思源如何添加自定义命令
2025-07-20 00:08这个可以
方法 1(适用于直接获取当前焦点文档)
function getProtyle() { try { if(document.getElementById("sidebar")) return window.siyuan.mobile.editor.protyle; const currDoc = window.siyuan?.layout?.centerLayout?.children.map(item=>item.children.find(item=>item.headElement?.classList.contains('item--focus') && (item.panelElement.closest('.layout__wnd--active')||item.panelElement.closest('[data-type="wnd"]')))).find(item=>item); return currDoc?.model.editor.protyle; } catch(e) { console.error(e); return null; } }
方法 2(适用于通过 closest 等获取到.protyle 元素后,再获取实例)
// 调用示例 getInstanceById('d428018f-82e8-4f7a-9c06-c3d192517b2d') function getInstanceById(id, layout = window.siyuan.layout.centerLayout) { const _getInstanceById = (item, id) => { if (item.id === id) return item; if (!item.children) return; let ret; for (let i = 0; i < item.children.length; i++) { ret = _getInstanceById(item.children[i], id); if (ret) return ret; } }; return _getInstanceById(layout, id); }
-
搜索字体属性?
2025-07-19 15:54找到方法了,先安装 [js] 告别 select * from blocks!嵌入块多字段查询来了 代码片段
然后嵌入块执行以下 SQL 即可,思源默认嵌入块不支持。
SELECT markdown, block_id as id__hide FROM spans WHERE markdown REGEXP 'style="color:\s*var\([^)]+?\);*"';
前面 @qiancang 提了一嘴,没太注意,刚才打算查看 attributes 表是否有 span_id 时发现 spans 表本身就有 markdown 字段。
-
搜索字体属性?
2025-07-19 14:56感谢采纳!
授之以鱼,不如授之以渔。
我说说这类需求查询思路吧。
1 先找一个或几个块做测试,标记上不同颜色
2 然后在数据库里查询这些块,看有什么规律
3 通过规律查询和筛选即可
比如,你这里的需求,我添加了三处标记
然后查询数据库得知,markdown 字段,如下
然后,你就可以根据规律去查询了.
比如,如果你想仅查询包含颜色标记,但不包含标记背景及背景和颜色同时标记的,可以这样查询。
SELECT * FROM blocks WHERE type='p' AND markdown REGEXP 'style="color:\s*var\([^)]+?\);*"';
如果自己找不出或不会写,可以把相关信息复制给 ai,让 ai 帮忙写。现在 ai 可以支持图片和视频,一般都没问题。
当然,可以按 J 佬说的用
attributes
表提高性能,比如SELECT * FROM blocks WHERE type='p' AND id IN ( SELECT block_id FROM attributes WHERE name = "style" AND value REGEXP '^color:\s*var\([^)]+?\);*$' );
注意,这里 attributes 表的数据和 blocks 表的格式略有不同,如下
其他样式也类似,思路都是相通的。
但要注意,这里只能查询到块,没办法仅显示行内标记颜色的元素,如果仅显示行内标记颜色的元素,这会变得更加复杂,估计得用 js 去实现了或尝试 spans 表查询。
spans 表查询方式,可参考 搜索字体属性? - wilsons 的回帖
-
[js] 不用插件:思源如何添加自定义命令
2025-07-19 07:31如果想完全不依赖插件,比如基础 Plugin,还是要写不少东西的,而且还要与现有插件兼容,太麻烦了。
都不如直接抛弃插件方案,自己实现想要的功能,哈哈。
-
手机端如何禁止左右滑动弹出文档树和设置菜单
2025-07-18 17:33把此代码放到 js 代码片段中即可
// 左右滑动时文档树和设置菜单同时禁用 if (!!document.getElementById("sidebar")) { const moveHandle = (e) => { if(e.target.closest('#menu, #sidebar')) return; document.getElementById("menu").style.transform = ""; document.getElementById("sidebar").style.transform = ""; const maskElement = document.querySelector(".side-mask"); maskElement.classList.add("fn__none"); maskElement.style.opacity = ""; }; document.addEventListener("touchmove", moveHandle, { passive: false}); document.addEventListener("touchend", moveHandle, { passive: false }); }
改进版,支持仅禁用一个
// 手机端禁止左右滑动弹出文档树和设置菜单 // 改进版,支持仅禁用一个 if (!!document.getElementById("sidebar")) { // 右滑不弹出文档树 true 不弹出 false 弹出 const disableFileTree = true; // 左滑不弹出设置菜单 true 不弹出 false 弹出 const disableSetingMenu = false; // 拖动开始 let startX = 0; document.addEventListener("touchstart", (e) => { if(e.target.closest('#menu, #sidebar')) return; const touch = e.touches[0]; startX = touch.clientX; // 记录初始X坐标 }, { passive: true }); // 拖动中 const hideMask = () => { const maskElement = document.querySelector(".side-mask"); maskElement.classList.add("fn__none"); maskElement.style.opacity = ""; }; const moveHandle = (e) => { if(e.target.closest('#menu, #sidebar')) return; if(disableSetingMenu) document.getElementById("menu").style.transform = ""; if(disableFileTree) document.getElementById("sidebar").style.transform = ""; if(disableFileTree && disableSetingMenu) { hideMask(); // 同时禁用 } else { // 仅禁用一个 const touch = e.touches[0]; const currentX = touch?.clientX||0; const diffX = currentX - startX; if (Math.abs(diffX) > 0) { if (diffX < 0) { // 左滑 设置菜单 if(disableSetingMenu) hideMask(); } else { // 右滑 文档树 if(disableFileTree) hideMask(); } startX = currentX; } } }; document.addEventListener("touchmove", moveHandle, { passive: false}); // 拖动结束 const endHandle = (e) => { if(e.target.closest('#menu, #sidebar')) return; if(disableSetingMenu) document.getElementById("menu").style.transform = ""; if(disableFileTree) document.getElementById("sidebar").style.transform = ""; hideMask(); }; document.addEventListener("touchend", endHandle, { passive: false }); }
高性能版
-
[js] Shift+F5 刷新页面
2025-07-17 22:29最新版刷新方法
see Issue #15308 · siyuan-note/siyuan
// Shift+F5 重载界面 JS片段 (()=>{ document.addEventListener('keydown', function(event) { // 检查是否同时按下了 Shift 和 F5 ,并且没有其他修饰键被按下 if (event.shiftKey && event.key === 'F5' && !event.ctrlKey && !event.altKey && !event.metaKey) { event.preventDefault(); // 阻止默认行为 reloadUI(); // 重载界面 API } }); // 刷新UI // mode app客户端 desktop浏览器桌面端 mobile移动端 // see https://github.com/siyuan-note/siyuan/issues/15308 function reloadUI(mode) { // 未安装插件 if(window.siyuan.ws.app.plugins?.length === 0) { if (mode) window.location.pathname = `stage/build/${mode}/`; else fetch('/api/ui/reloadUI', { method: 'POST' }); return; } // 获取plugin const plugin = window.siyuan.ws.app.plugins[0]; // 旧版 if(!plugin?.saveLayout) { if (mode) window.location.pathname = `stage/build/${mode}/`; else fetch('/api/ui/reloadUI', { method: 'POST' }); return; } // 新版 plugin.saveLayout(() => { if (mode) window.location.pathname = `stage/build/${mode}/`; else window.location.reload(); }); } })();
-
属性引用:彻底解决引用丢失问题,方案可行性探讨和投票
2025-07-16 19:38 -
docker 搭建的思源笔记如何与本地客户端思源笔记同步?
2025-07-16 16:27docker 实际上只是一个普通的客户端而已(这点容易被人误解为其他端提供服务的服务端)。
借贴说说思源的架构和客户端、docker 之间的关系。
总体来说,思源架构是:客户端(前端)+ 内核(提供 api 调用的后端服务)
桌面客户端:electron 作为客户端 + golang 内核(api)
移动端:客户端嵌入 webview + golang 内核(api)
docker:浏览器作为客户端 + golang 内核(api)
说白了无论 electron、webview、浏览器,本质都是基于 webui。
所以,docker 其实和其他端没有任何区别,无非是客户端实现技术不同罢了。
-
我需要在数据库中使用模板语法计算股票交易的移动平均成本
2025-07-16 11:37是的,你想多了,没有说要写到数据库外部,写到数据库模板里即可,因为数据库模板支持 html 格式。
为什么是 img 标签,因为可以利用 onerror 执行 js,这是 hack 方法。
不能直接写 js 片段,会被过滤或转换为实体,不会被执行。
api 在哪里?参考 https://www.siyuan-note.club/6992007m0
-
求段小代码:隐藏文档树的各种弹框
2025-07-15 19:32不需要 js,css 即可
.sy__file .b3-tooltips:hover::before, .sy__file .b3-tooltips:hover::after, /* 隐藏更多新建提示 */ body:has(.sy__file .b3-list-item--hide-action:hover>.b3-list-item__action) #tooltip /* 隐藏文档信息提示 */ { display: none; }
-
/data/assets/ 目录下的图片会被加密,有什么解决办法吗
2025-07-15 16:06还有两个办法
1 图片改扩展名,比如统一添加后缀.xxx,试试是否还会加密
2 粘贴为 base64 图片不过这两种方式需要自己拦截思源的默认操作或者自己添加右键菜单实现。
第 1 种办法如果可行,可以外部监听文件夹添加文件,在加密前重命名,如果可以的话,思源就无需任何改动了。
-
[js] 粘贴为链接(可自动获取文章标题)
2025-07-15 15:14🖱️ 右键轻唤,链接如星现。
🕰️ 往昔寻题心倦,思绪纷乱如线。
✨ 今朝妙技巧呈祥,粘来自带华章。
💡 不费丝毫气力,逍遥意韵悠长。 -
请教数据库中模版函数的用法
2025-07-15 13:021 和 2
.action{$result := querySQL (replace "?" .主键 "SELECT count(*) as count FROM blocks WHERE type ='h' AND hpath like '%?%'")} .action{ $f := first $result} .action{$f.count}
或
.action{$blocks := queryBlocks "SELECT * FROM blocks WHERE type ='h' AND hpath like '%?%'" .主键} .action{ $count := len $blocks} .action{$count}
3 换个思路,既然添加文档时插入不好实现,可以在打开数据库文档时查询后插入嘛
-
我需要在数据库中使用模板语法计算股票交易的移动平均成本
2025-07-14 21:44正如 J 佬所说,单依靠模板语法无法实现。
模板语法不支持调 api,不过,可以这样
<img src onerror=" // 代码写这里 " />
然后就可以愉快的调 api 了
1 先通过数据库 api 获取数据库的完整数据(或通过 dom 遍历)
2 根据 this 找出本单元格的列 id 和行 id
3 然后,你想怎么算就怎么算了
4 结果赋值给 this.ouerHTML 即可
对了,为了防止多次获取数据,造成资源浪费,最好把获取结果放到固定对象上,比如这里的表格 dom 对象,如果已存在无需再次获取,只需读取即可。