highlight.js支持动态代码

393 阅读2分钟

背景

最近在做一个根据json自动生成java vo, ts interface, go struct的小工具,前端使用vue3 + typescript来实现。为了更好的用户体验,决定使用highlight.js来做生成代码的语法高亮。在使用过程中,发现只有第一次生成的代码可以语法高亮,后续再生成就不支持语法高亮了。通过搜索发现highlight.js不支持动态代码的高亮。

目标

通过改造,可以支持动态代码的高亮

解决方法

首先我们看下基础的使用

首先是html骨架

<div class="output-section">
<pre><code id="code" :class="targetLanguage">{{ outputClass }}</code></pre>
</div>

然后是语法高亮渲染

const convertJson = () => {
try {
const jsonObj = JSON.parse(inputJson.value);
outputClass.value = generateClassDefinition(jsonObj, targetLanguage.value);
console.log(outputClass.value);
nextTick(() => {
const codeElement = document.getElementById('code');
hljs.highlightElement(codeElement!);
});
} catch (error) {
outputClass.value = '❌ 无效的JSON格式';
}
};

这里通过nextTick实现对于code元素渲染后的高亮操作

我们可以看下渲染后的dom

<code data-v-f51febca="" id="code" class="java hljs language-java" data-highlighted="yes"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">AutoGenerated</span> {
<span class="hljs-keyword">private</span> <span class="hljs-type">int</span> age;
<span class="hljs-keyword">private</span> String name;
}
</code>

我们可以发现,如果不使用highlight.js,理论上生成的code,内容应该就是一个标准字符串,使用后highlight.js增加了一些span元素进去

那么,我们可以不可以每次需要重新渲染时,就将code的内容改变,重新调用一次hightlight.js呢?我们先试一下

改造后的代码如下

const convertJson = () => {
try {
const jsonObj = JSON.parse(inputJson.value);
outputClass.value = generateClassDefinition(jsonObj, targetLanguage.value);
console.log(outputClass.value);
nextTick(() => {
const codeElement = document.getElementById('code');
if (codeElement) {
// 先移除所有highlight相关的class
codeElement.className = targetLanguage.value;
// 强制重新渲染
codeElement.innerHTML = outputClass.value;

}
// 重新应用highlight
hljs.highlightElement(codeElement!);
});
} catch (error) {
outputClass.value = '❌ 无效的JSON格式';
}
};

相比之前的变化是,多了一次判断,就判断codeElement已经存在的话,通过innerHTML先修改code元素的值,然后再通过highlight.js来做语法高亮。修改完成之后,发现还是只有第一次可以语法高亮,而且后面的dom中也没有span之类的标签了

i继续观察dom,发现相比预期,code元素多了一个属性data-highlighted="yes",有理由怀疑highlight.js是根据这个属性来判断要不要做高亮操作。尝试着移除这个属性试试。改造后的代码如下

const convertJson = () => {
try {
const jsonObj = JSON.parse(inputJson.value);
outputClass.value = generateClassDefinition(jsonObj, targetLanguage.value);
console.log(outputClass.value);
nextTick(() => {
const codeElement = document.getElementById('code');
if (codeElement) {
// 先移除所有highlight相关的class
codeElement.className = targetLanguage.value;
// 强制重新渲染
codeElement.innerHTML = outputClass.value;
// 移除属性k
codeElement.removeAttribute('data-highlighted');
}
// 重新应用highlight
hljs.highlightElement(codeElement!);
});
} catch (error) {
outputClass.value = '❌ 无效的JSON格式';
}
};

这里多了一行,即通过removeAttribute方法来移除已有的属性,再次尝试,果然可以了。

广告

工具地址

kennethfan.github.io/web-tools/j…

这是一个个人开发的工具集,代码已经分享到github,欢迎各位共建

github.com/kennethfan/…

参考

highlightjs.org/

github.com/highlightjs…