Markdown编辑器如何实现代码块高亮并保留缩进?

司徒心虹 阅读 14

我在用Vue项目集成Markdown编辑器时卡住了。用了marked库渲染,代码块能显示但没有高亮,手动引入highlight.js后虽然能高亮了,但输入的缩进会被浏览器自动压缩成一个空格,代码看起来乱糟糟的。比如写:

<script>
function test() {
  console.log('缩进全没了')
}
</script>

渲染后代码块里的缩进全变成单空格,而且高亮只对第一行生效。试过设置

标签的tabIndex属性和添加preserveSpaces配置,但都没用。搞不懂为啥marked和highlight.js配合时会出现这种情况,有没有更好的解决办法?

我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
露露 ☘︎
你这问题出在两个地方,一个是marked的配置没对,另一个是highlight.js的调用时机错了。

首先,marked默认会把代码里的空格和制表符处理掉,得手动关掉这个行为。你初始化marked的时候要加个选项:mangle: falseheaderIds: false 其实不关键,重点是你要确保传给marked的源文本里缩进是保留的,而且渲染时不要让DOM自动吃掉空白。

真正的解法是配合CSS和正确的API调用顺序。先装好highlight.js,然后这么配marked:

import marked from 'marked';
import hljs from 'highlight.js';

// 设置marked的renderer
const renderer = new marked.Renderer();
renderer.code = function(code, lang) {
// 确保lang存在就高亮,否则也保留code原样
const validLang = !!hljs.getLanguage(lang) ? lang : 'plaintext';
const highlighted = hljs.highlight(validLang, code).value;
return
${highlighted}
;
};

// 设置marked使用这个renderer
marked.setOptions({ renderer });


注意这里直接返回了带pre包裹的结构,因为代码块必须在外层用pre才能保留空白。然后你在CSS里加上:

code.hljs {
white-space: pre;
word-wrap: normal;
overflow: auto;
padding: 1em;
}


white-space设成pre或者pre-wrap是关键,不然浏览器会把多个空格合并。

还有个常见坑是你可能在Vue里用v-html直接插字符串,但数据流不对的话,highlight.js可能会在DOM更新前就跑完了。如果你发现高亮不生效,别用mounted里一次性调,改成用nextTick或者watch文本变化后手动触发一次highlight,或者干脆全交给marked在render阶段做完。

最后建议换prism.js也行,但它也有类似问题。最稳的方式还是我上面写的——在marked的code渲染钩子里直接调用highlight.js API完成高亮,这样流程可控,缩进也能保住。
点赞 3
2026-02-11 09:05