最近看社区有格式刷需求,以及自己也有需求,因此开发了格式刷插件:Achuan-2/siyuan-plugin-formatPainter: Use the format painter to batch apply styles (github.com)
觉得好用的欢迎点个 star
自己没正经学过 js,很大部分靠 GPT 实现的代码
下面整理下自己的开发笔记,欢迎大家互相交流学习
开发笔记
-
❓ 如何设置选中内容的样式
protyle.toolbar.setInlineMark
- 设置行内块样式
// datatype:"kbd", "text", "strong", "em", "u", "s", "mark", "sup", "sub", "code" this.protyle.toolbar.setInlineMark(this.protyle, datatype, "range");
- 设置背景颜色
this.protyle.toolbar.setInlineMark(this.protyle, "text", "range", { "type": "backgroundColor", "color": backgroundColor });
- 设置字体颜色
this.protyle.toolbar.setInlineMark(this.protyle, "text", "range", { "type": "color", "color": color });
- 设置字体大小
this.protyle.toolbar.setInlineMark(this.protyle, "text", "range", { "type": "fontSize", "color": fontSize });
- 输入 style,如何自动设置背景色、字体色、字体大小
const { backgroundColor, color, fontSize } = parseStyle(this.formatData.style); // console.log(backgroundColor, color, fontSize); if (backgroundColor) { this.protyle.toolbar.setInlineMark(this.protyle, "text", "range", { "type": "backgroundColor", "color": backgroundColor }); } if (color) { this.protyle.toolbar.setInlineMark(this.protyle, "text", "range", { "type": "color", "color": color }); } if (fontSize) { this.protyle.toolbar.setInlineMark(this.protyle, "text", "range", { "type": "fontSize", "color": fontSize }); } } function parseStyle(styleString) { const styles = styleString.split(';').filter(s => s.trim() !== ''); const styleObject = {}; styles.forEach(style => { const [property, value] = style.split(':').map(s => s.trim()); styleObject[property] = value; }); return { backgroundColor: styleObject['background-color'], color: styleObject['color'], fontSize: styleObject['font-size'] }; }
- 设置行内块样式
-
❓ 如何获取选中文本的样式,并且如果返回的节点是 span,则提取出其 data-type 和 style 内容
对数学公式块做了特别处理,因为数学公式块的的 range.startContainer 是它前面的节点而不是它自己,会导致获取节点错误。
function getSelectedParentHtml() { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); let selectedNode = range.startContainer; const endNode = range.endContainer; // 检查 endNode 的 previousSibling if (endNode.previousSibling && endNode.previousSibling.nodeType === Node.ELEMENT_NODE) { const previousSibling = endNode.previousSibling; if (previousSibling.tagName.toLowerCase() === "span" && previousSibling.classList.contains("render-node")) { selectedNode = previousSibling; } } let parentElement = selectedNode.nodeType === Node.TEXT_NODE ? selectedNode.parentNode : selectedNode; while (parentElement && !parentElement.hasAttribute("data-type")) { parentElement = parentElement.parentElement; } if (parentElement && parentElement.tagName.toLowerCase() === "span") { const result = { html: parentElement.outerHTML, datatype: parentElement.getAttribute("data-type"), style: parentElement.getAttribute("style") }; // 清空选区 selection.removeAllRanges(); return result; } } // 清空选区 selection.removeAllRanges(); return null; }
-
❓ 设置格式刷模式
- 设置格式刷模式变量:搞一个变量 FormatPainterEnable,默认为 false,点击时如果为 false,则获取选中文本的其 data-subtype 和 style 内容,FormatPainterEnable=true。
- 之后选中文本并抬起鼠标后进行格式刷操作:监听 mouseup 和 window.getSelection();
- 按 esc 键,退出格式刷模式,设置 FormatPainterEnable=false:监听 esc 键按下,如果 FormatPainterEnable=true 则设置为 false;
-
❓ 如何进入格式刷和退出格式刷模式推送信息
import { fetchPost, } from "siyuan"; // 进入格式刷模式 fetchPost("/api/notification/pushErrMsg", { "msg": this.i18n.enable, "timeout": 7000 }); // 退出格式刷模式 fetchPost("/api/notification/pushMsg", { "msg": this.i18n.disable, "timeout": 7000 });
-
❓ 点击格式刷,如何关闭工具栏?
// 关闭toolbar // 选择所有具有 .protyle-toolbar 类的元素 const toolbarElements = document.querySelectorAll('.protyle-toolbar'); // 遍历选中的元素 toolbarElements.forEach(element => { // 检查元素是否没有 .fn__none 类 if (!element.classList.contains('fn__none')) { // 如果没有 .fn__none 类,则添加它 element.classList.add('fn__none'); } });
-
❓ 如何修改光标
用 css 修改,因为 js 修改如果新打开窗口,就不方便再修改了- 启动格式刷时,给 body 添加自定义属性 formatPainterEnable=true, 通过 css 更改光标
- 禁用格式刷,给 body 添加自定义属性 formatPainterEnable=false,通过 css 改回光标
body[data-format-painter-enable="true"] .protyle-wysiwyg { cursor: url("plugins/siyuan-plugin-formatPainter/assets/formatPainter_mouse2.png"), auto; } body[data-format-painter-enable="false"] .protyle-wysiwyg { cursor: auto; }
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于