更完整的代码片段见:[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 } : "";
}
}
})();
预览
没处理前:块公式惨不忍睹,行内公式有些看着正常,但是手机一预览一旦有下标、上标就会跑到其他地方去
代码片段运行后:行内公式和公式块都以 svg 格式插入公式,一切正常
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于