-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
插件开发求助:想问问有什么方法能获取到最新又完整的文档DOM结构呢 #13313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
这是思源机制的根本矛盾,因为思源在编辑后,必须写入了文档,重新读取,才能获得更新后的文档。所以是比较无解的。 目前只能要么你定死一个等待时间,要么用新开一个ws进行监听,发现更新后在获取md内容。 当然还有一个一劳永逸的方案:劝说D实现ast持久化,就像我在ld帖子里捣鼓的那样。这样就不需要写入后重新读取也能获得更新内容了 :) |
哦哦,好的,谢谢大佬回复 |
还是得持久化的,不然某些极端情况(比如掉电或者宕机)可能会导致数据未写入丢失。 后面可能可以考虑通过内存映射方案实现更好的 IO,这个 issue 我先关闭了,楼主可以试下监听 websocket transactions。 |
ws 不会写,暂时先用 await new Promise(resolve => setTimeout(resolve, 500));顶顶吧 |
调用完成后用 |
我需要文档完整的dom,进行批量替换,怕思源的动态加载机制,获得的不是完整的dom |
setInlineMark 和 insert 后是完整的。 |
ok,我试试,谢谢v姐 |
哇可以的,想问问protyle.wysiwyg.element修改后,怎么保存呢,
|
保存为变量还是文本? DOM 上有很多事件的,没看明白需求和这个解决方案。 |
我的需求是,脚注插件如果要有序编号的话,需要更新全部的脚注块引锚文本,以及对末尾的脚注内容块位置进行重排, |
脚注的 div 是如何得到的?每次刷新的时候再按照这个方法获取填充就可以了吧。 要让脚注保存为思源文件的话,需要按照块的形式放置在 wysiwyg.element 元素内就可以了。 |
插件添加的内容都加了自定义属性,能直接找到,都是直接用思源原生的块实现的 我直接修改wysiwyg.element,寻找并替换块引锚文本,对有特定自定义属性的块进行重排,看样子是修改了,按f5刷新,就又到原来样子了,用上面的saveViaTransaction,只能保存修改的块引,重排的div保存不了,于是我只能用更耗时的updateBlock,把修改后的wysiwyg.element传入进行保存,能保存成功,但是体验不是很好,耗时,会导致块临时丢失再恢复 |
没有动态加载出来也能改吗 |
修改完以后调用 "/api/transactions" 这个接口应该就可以持久化了
|
好滴谢谢v姐,那请问为什么我wysiwyg.element获取的html不是完整的dom呢,只有动态加载的部分 我是在工具栏添加按钮,把protyle.protyle 传给生成脚注的函数,再用protyle.protyle.wysiwyg.element来替换内容,https://github.com/Achuan-2/siyuan-plugin-blockref-footnote/blob/35f420a08e88702ef22da2bd3812dc65d02a8227/src/index.ts#L1132 |
动态的话,只会加载部分,界面不会卡顿。可以监听 |
我也没太懂大佬们说的ws监听,不过我尝试了下,可能大佬们说的是这样吧,你可以试试看。 @88250 @zxhd863943427 不对的地方请帮忙指正!谢谢! // see https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/app/src/layout/Model.ts
(() => {
// 创建socket客户端
createSocketClient(siyuan.ws.ws.url);
// 当收到消息时被调用
function onReceivedMessage(event) {
const message = parseJson(event.data);
if(message.cmd === 'transactions') {
// 这里获取更新后的数据
console.log(message);
}
}
// 创建socket客户端
function createSocketClient(url) {
// 连接 WebSocket 服务器
const socket = new WebSocket(url);
socket.onopen = function(event) {
console.log('WebSocket opened');
};
socket.onmessage = onReceivedMessage;
socket.onclose = function(event) {
console.log('WebSocket closed!');
};
socket.onerror = function(error) {
console.error('WebSocket Error:', error);
};
return socket;
}
// 客户端向服务器发送消息
function sendMessage(socket, message) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(message);
} else {
console.error('WebSocket connection is not open');
}
}
// 解析json
function parseJson(jsonString) {
let json = {};
try {
json = JSON.parse(jsonString || '{}');
} catch(e) {
json = {};
console.error('parseJson error', e);
}
return json;
}
})() |
确实可以,刚才写了个测试代码 测试代码// see https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/app/src/layout/Model.ts (() => { // 创建socket客户端 createSocketClient(siyuan.ws.ws.url); |
@wish5115 学习了,我之后尝试下 |
又得一简便方法,不用再次启动客户端监听了,只需要监听思源已有的客户端的消息事件即可,如下 siyuan.ws.ws.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
if(msg.cmd === "transactions") {
// 这里获取更新后的数据
console.log(msg);
}
}); 而且,之前的方法中, URL参数中的id参数最好重新生成,不然可能与思源已有会话id一样,详见 https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/kernel/util/websocket.go |
@wish5115 哇,感谢大佬 |
终极方案。 封装成了仅调用一次的便捷方案。 如果持续监听用原生更方便。 // 当块被保存时执行回调(仅执行一次)
function whenBlockSaved(filter) {
return new Promise((resolve, reject) => {
const ws = siyuan.ws.ws;
const clearEvent = () => ws.removeEventListener('message', handler);
const handler = (event) => {
try {
const msg = JSON.parse(event.data);
if(msg.cmd === "transactions") {
if(typeof filter === 'function') {
if(filter(msg)) resolve(msg);
} else {
resolve(msg);
}
clearEvent();
}
} catch(e) {
reject(e);
clearEvent();
}
}
clearEvent();
ws.addEventListener('message', handler);
});
}
// 调用示例
// 链式调用
// whenBlockSaved().then((msg) => {
// console.log(msg);
// });
// 异步调用
// const msg = await whenBlockSaved();
// console.log(msg);
// 过滤条件
// whenBlockSaved(msg => {
// return msg.data.find(item => item.doOperations.find(item2 => item2.action === 'update' && item2.id === '20241204115642-hmpp8kh'));
// }).then((msg) => {
// console.log(msg);
// });
// const filter = msg => msg.data.find(item => item.doOperations.find(item2 => item2.action === 'update' && item2.id === '20241204115642-hmpp8kh'));
// const msg = await whenBlockSaved(filter);
// console.log(msg); |
Uh oh!
There was an error while loading. Please reload this page.
In what scenarios do you need this feature?
发现用protyle.protyle.toolbar.setInlineMark添加样式和protyle.insert插入文字后
立即用/api/filetree/getDoc和/api/block/getBlockKramdown,获取不到最近插入的样式,需要等500ms,才能获取到最新的完整DOM
而直接用document的DOM结构又获取不到完整的DOM结构
Describe the optimal solution
想问问有什么帮法能获取到最新的DOM结构呢
Describe the candidate solution
No response
Other information
No response
The text was updated successfully, but these errors were encountered: