highlight.js支持动态代码

背景

最近在做一个根据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方法来移除已有的属性,再次尝试,果然可以了。

广告

工具地址

https://kennethfan.github.io/web-tools/json-to-class

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

https://github.com/kennethfan/web-tools

参考

https://highlightjs.org/ \ https://github.com/highlightjs/highlight.js

results matching ""

    No results matching ""