【问题标题】:How can I correctly highlight a line by line code, using highlight.js (React)?如何使用 highlight.js (React) 正确地突出显示一行代码?
【发布时间】:2021-01-24 13:55:59
【问题描述】:

我需要突出显示一段代码,但同时,我需要将代码放在单独的编号行上,以便为每一行代码保留 cmets,就像在 Github 上所做的那样。我设法做到了这一点,但是因为我突出显示了每一行的代码,所以不会正确突出显示多行上的“SQL”代码(仅突出显示第一行)并且我无法解决此问题。你有什么建议吗?

       if (data.success === 1) {
          setCodeLanguage(translateLanguage(data.code.language));
          let rows = [];
          data.code.source_code.split("\n").forEach((line, index) => {
            rows.push(
              <tr key={index} className="line">
                <td className="line-number">{index + 1}</td>
                <td id={"plus" + index} className="plus-square-line">
                  <PlusSquareTwoTone className="plus-square" />
                </td>
                <td id={"codeblock" + index}
                  className={'language-' + codeLanguage} style={rowStyle}>
                  {line}
                </td>
              </tr>
            );
          });
          setCodeRows(rows);
          for (let i = 0; i < codeRows.length; ++i) {
            hljs.highlightBlock(document.getElementById("codeblock" + i));
          } 

【问题讨论】:

    标签: javascript reactjs highlight.js


    【解决方案1】:

    您不能简单地在\n 上拆分输出,因为跨度可以跨越行边界:

    var x = <span class="string>"This is a
    really long string
    that spans multiple lines
    super annoying"</span>
    

    你必须写代码把它变成:

    var x = <span class="string">"This is a</span>
    <span class="string">really long string</span>
    <span class="string">that spans multiple lines</span>
    <span class="string">super annoying"</span>
    

    IE,在任何给定时刻,您都必须跟踪所有打开的标签,并在一行结束时关闭它们,然后在下一行开始之前打开它们。

    可以说这并不是 Highlight.js 的典型用例,因此您可以自己构建它。


    没有简单的方法可以做到这一点,但是如果您访问原始解析树(而不是生成的 HTML),您可以编写一些内容逐个节点遍历它并找出行的位置是。如何访问解析树对象(发射器):

    highlight(code).__emitter
    

    或者您可以简单地将发射器替换为您自己的自定义发射器。查看源文件以了解您需要实现的 API:

    https://github.com/highlightjs/highlight.js/blob/master/src/lib/token_tree.js

    然后你必须走在树上,跟踪哪些标签是打开的,当你发现一行结束时,你需要关闭标签……在下一行重新打开它们。 IE,几乎你需要从解析树开始,编写自己的HTML渲染引擎。

    请注意:整个__emitter API 不被视为公共 API 的一部分,并且可能在未来的更新中随时更改或中断 - 尽管通常只要您确保使用它应该“相当安全”测试新版本。我没有计划在不久的将来对其进行重大更改。

    [声明:我是当前的 Highlight.js 维护者。]

    【讨论】:

      【解决方案2】:

      我们最近不得不实现行号,这是我们在 Typescript 中的实现,以将其添加为插件:

      hljs.addPlugin({
        "after:highlight": (params: { value: string; }) => {
          const openTags: string[] = [];
          
          params.value = params.value.replace(/(<span [^>]+>)|(<\/span>)|(\n)/g, match => {
            if (match === "\n") {
              return "</span>".repeat(openTags.length) + "\n" + openTags.join("");
            }
            
            if (match === "</span>") {
              openTags.pop();
            } else {
              openTags.push(match);
            }
            
            return match;
          });
        },
      });
      

      这会将highlightjs 输出的字符串更改为\n 可以轻松拆分的字符串。

      如果您在客户端执行此操作,您可能希望使用 "after:highlightBlock""after:highlightElement" 代替,具体取决于 highlightjs 的版本。

      或者您可以只调用输出上的函数,然后将其拆分为\n

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-16
        • 1970-01-01
        • 1970-01-01
        • 2018-12-09
        • 2018-06-24
        • 2012-02-28
        相关资源
        最近更新 更多