[js] 用代码片段让思源笔记发布到微信公众号支持公式渲染

更完整的代码片段见:[js] 思源笔记粘贴到微信公众号处理公式、链接、多级列表 - 链滴


最近沉迷统计学,打算在微信公众号发统计分析的笔记,但是思源笔记不支持粘贴公式到微信公众号,行内公式和块级公式都不行,非常苦恼

之前提了这个 issue,发布到微信公众号支持公式渲染 · Issue #12571 · siyuan-note/siyuan,等 DV 两口子解决也是遥遥无期

只好自己尝试解决了,因为正好知道微信 Markdown 编辑器 | Doocs 开源社区这个编辑器是支持 markdown 公式粘贴到微信公众号,于是扒代码,把代码发给 GPT 如何改进思源笔记的预览模式……花了一小时

竟然真的给我问出来了哈哈哈

代码片段

(async () => { // 定义观察DOM变化的函数 function observeDomChange(targetNode, callback) { const config = { childList: true, subtree: true }; const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { callback(mutation); } } }); observer.observe(targetNode, config); return observer; } const targetNode = document.body; // 开始观察DOM变化,并在检测到.color__square元素时运行updateColors observeDomChange(targetNode, async (mutation) => { const hasMathBlock = mutation.target.querySelector('.layout__wnd--active .protyle:not(.fn__none) .protyle-preview>.b3-typography div[data-subtype="math"]:not([data-repleaced="true"])'); const hasInlineMath = mutation.target.querySelector('.layout__wnd--active .protyle:not(.fn__none) .protyle-preview>.b3-typography span[data-type="inline-math"]:not([data-repleaced="true"])'); if (mutation.target.classList.contains("protyle-preview")) { if (hasMathBlock || hasInlineMath) { await fetchSyncPost('/api/notification/pushMsg', { "msg": "正在处理公式", "timeout": 5000 }); loadMathJax(async () => { await Promise.all([renderMathBlocks(), renderInlineMath()]); console.log('MathJax has been loaded!'); await fetchSyncPost('/api/notification/pushMsg', { "msg": "公式处理完毕", "timeout": 5000 }); }); } } }); function createRenderer(display) { return (mathContent) => { const cleanedContent = mathContent.replace(/\\displaystyle\s*{([^}]*)}/g, '$1'); window.MathJax.texReset(); const mjxContainer = window.MathJax.tex2svg(cleanedContent, { display }); const svg = mjxContainer.firstChild; const width = svg.style[`min-width`] || svg.getAttribute(`width`); svg.removeAttribute(`width`); svg.style = `max-width: 70vw !important;`; svg.style.width = width; svg.style.display = `initial`; if (display) { return `<section style="box-sizing: border-box; border-width: 0px; border-style: solid; border-color: hsl(var(--border)); user-select: text !important; color: rgb(10, 10, 10); font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; text-align: center; overflow: auto;">${svg.outerHTML}</section>`; } return svg.outerHTML; }; } async function renderMathBlocks() { const mathBlocks = document.querySelectorAll('.b3-typography div[data-subtype="math"]:not([data-repleaced="true"])'); const renderBlock = createRenderer(true); return Promise.all(Array.from(mathBlocks).map(async (block) => { const mathContent = block.getAttribute('data-content'); try { block.innerHTML = renderBlock(mathContent); block.setAttribute('data-repleaced', 'true'); } catch (error) { console.error('Error rendering MathJax block:', error); } })); } async function renderInlineMath() { const inlineMaths = document.querySelectorAll('span[data-type="inline-math"]:not([data-repleaced="true"])'); const renderInline = createRenderer(false); return Promise.all(Array.from(inlineMaths).map(async (span) => { const mathContent = span.getAttribute('data-content'); try { span.innerHTML = renderInline(mathContent); span.style.verticalAlign = 'middle'; span.style.lineHeight = '1'; span.setAttribute('data-repleaced', 'true'); } catch (error) { console.error('Error rendering MathJax inline:', error); } })); } function loadMathJax(callback) { window.MathJax = { tex: { inlineMath: [['$', '$'], ['\\(', '\\)']] }, svg: { fontCache: 'none' } }; const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js'; script.async = true; script.onload = callback; document.head.appendChild(script); } async function fetchSyncPost(url, data, returnType = 'json') { const init = { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }; try { const res = await fetch(url, init); return returnType === 'json' ? await res.json() : await res.text(); } catch (e) { console.log(e); return returnType === 'json' ? { code: e.code || 1, msg: e.message || "", data: null } : ""; } } })();

预览

没处理前:块公式惨不忍睹,行内公式有些看着正常,但是手机一预览一旦有下标、上标就会跑到其他地方去

PixPin20241114001310.png

代码片段运行后:行内公式和公式块都以 svg 格式插入公式,一切正常

PixPin20241114001220.png

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25540 引用 • 105644 回帖 • 2 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    172 引用 • 1165 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    90 引用 • 122 回帖 • 620 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    37 引用 • 157 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 4 关注
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 6 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    52 引用 • 190 回帖
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 141 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 638 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 343 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 466 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 634 关注
  • 印象笔记
    3 引用 • 16 回帖 • 1 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 6 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    184 引用 • 1020 回帖
  • gRpc
    11 引用 • 9 回帖 • 92 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    369 引用 • 1846 回帖 • 3 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    336 引用 • 324 回帖
  • OneDrive
    2 引用
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 666 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 53 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖 • 3 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1441 引用 • 10069 回帖 • 497 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • 禅道

    禅道是一款国产的开源项目管理软件,她的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

    7 引用 • 15 回帖 • 9 关注