背景
最近在做一个根据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方法来移除已有的属性,再次尝试,果然可以了。
广告
工具地址
这是一个个人开发的工具集,代码已经分享到github,欢迎各位共建
参考