一、背景

笔者在开发这套博客系统时使用 Editormd 作为 Markdown 编辑器,由于不满足其代码高亮的样式,因此选用 highlight.js 插件来实现代码高亮功能。但是,highlight.js 插件不提供行号的设置功能,于是有了该文章。

二、实现原理

html 的代码块都是通过 <code></code> 进行封装,我们可以将其内容取出封装到 <ol><li></li></ol> 从而实现设置行号的效果。

三、实现方式

下边提供两种实现方式。

# 3.1 后端修饰

笔者使用的是 commonmark 库来实现 markdown 转换成 html。

# 3.1.1 添加依赖:

  1. <dependency>
  2. <groupId>com.atlassian.commonmark</groupId>
  3. <artifactId>commonmark</artifactId>
  4. <version>0.11.0</version>
  5. </dependency>

# 3.1.2 工具类:

  1. public abstract class MarkdownUtil {
  2. public static List<Extension> extensions = Arrays.asList(TablesExtension.create());
  3. private static final Parser parser = Parser.builder().extensions(extensions).build();
  4. private static final HtmlRenderer renderer = HtmlRenderer.builder().extensions(extensions)
  5. // 修饰代码块内容
  6. .nodeRendererFactory(context -> new NodeRenderer() {
  7. @Override
  8. public Set<Class<? extends Node>> getNodeTypes() {
  9. return Collections.singleton(FencedCodeBlock.class);
  10. }
  11. @Override
  12. public void render(Node node) {
  13. HtmlWriter html = context.getWriter();
  14. FencedCodeBlock codeBlock = (FencedCodeBlock) node;
  15. Map<String,String> attrs = new HashMap<>();
  16. if (!StringUtils.isEmpty(codeBlock.getInfo())) {
  17. attrs.put("class","language-" + codeBlock.getInfo());
  18. }
  19. html.line();
  20. html.tag("pre");
  21. html.tag("code",attrs);
  22. html.tag("ol");
  23. String data = codeBlock.getLiteral();
  24. String[] split = data.split("\n");
  25. for (String s : split) {
  26. html.tag("li");
  27. html.text(s + "\n");
  28. html.tag("/li");
  29. }
  30. html.tag("/ol");
  31. html.tag("/code");
  32. html.tag("/pre");
  33. html.line();
  34. }
  35. }).build();
  36. /**
  37. * markdown 转 html
  38. * @param markdown
  39. * @return
  40. */
  41. public static String md2html(String markdown) {
  42. Node document = parser.parse(markdown);
  43. String result = renderer.render(document);
  44. return result;
  45. }
  46. }

如果不使用上边的 NodeRendererFactory 对 html 进行修饰,输出的 html 的代码块就只是 <pre><code></code></pre> 的形式。

# 3.2 前端修饰

使用 js 代码实现代码修饰:

  1. $("code").each(function(){
  2. $(this).html("<ol><li>" + $(this).html().replace(/\n/g,"\n</li><li>") +"\n</li></ol>");
  3. });

# 3.3 css 样式

由于 <ol><li></li></ol> 默认行号效果不友好,我们进行样式设置。

  1. .hljs {
  2. border: 0;
  3. font-size: 12px;
  4. display: block;
  5. padding: 1px;
  6. margin: 0;
  7. width: 100%;
  8. font-weight: 200;
  9. color: #333;
  10. white-space: pre-wrap
  11. }
  12. .hljs ol {
  13. list-style: decimal;
  14. margin: 0px 0px 0 40px !important;
  15. padding: 0px;
  16. }
  17. .hljs ol li {
  18. list-style: decimal-leading-zero;
  19. border-left: 1px solid #ddd !important;
  20. padding: 5px!important;
  21. margin: 0 !important;
  22. white-space: pre;
  23. }

实现的效果正是读者正在看到的效果。