给marked增加TOC(Table of content)

一直使用marked库解析Markdown,现在想给它增加TOC功能
使用marked解析markdown文本是很简单的,如:marked(markdownText)就可以得到解析后的html内容

初始化marked

引入库

var marked = require('marked');

重写renderer.heading

tocObj后面再介绍,返回的header中包含了用于定位的锚点。当然你也可以直接将锚点写在h标签中,我这里单独用一个a标签是为了解决,网站有固定的导航头的时候,定位锚点的时候标题被遮盖的问题,如:点击带锚点的网址后,如何让网页位置向下偏移一小段距离

var renderer = new marked.Renderer();
renderer.heading = function(text, level, raw) {
  var anchor = tocObj.add(text, level);
  return `<a id=${anchor} class="anchor-fix"></a><h${level}>${text}</h${level}>\n`;
};

设置参数

highlight是我用来处理代码高亮的,这里不考虑。

marked.setOptions({
    renderer: renderer,
    highlight: function(code) {
      return require("highlight.js").highlightAuto(code).value;
    },
});

保存marked解析后的header信息

在renderer.heading使用tocObj保存h标签的text和level并且返回一个生产的锚点,text即标签的内容,level是几级标题,如:h1,h2,h3等

产生toc的html代码

有了header信息就可以生成toc了,toc是根据h标签的等级层次来生成的,跟目录树是一样的,并不是一个单纯的列表平铺下来的。

我们目前拿到的数据是这样的,数字是level,标题是text,它们按顺序存放在数组中

h1一级标题
h1一级标题
  h2二级标题
  h2二级标题
    h3三级标题
  h2二级标题
h1一级标题

现在要把这些数据转换成html标签的形式

用ul和li标签来表示,就存在ul中嵌套ul的情况,如下:

<ul>
  <li>一级标题</li>
  <li>一级标题</li>
  <ul>
    <li>二级标题</li>
    <li>二级标题</li>
    <ul>
      <li>三级标题</li>
    </ul>
    <li>二级标题</li>
  </ul>
  <li>一级标题</li>
</ul>

转换代码

const tocObj = { 
  add: function(text, level) {
    var anchor = `#toc${level}${++this.index}`;
    this.toc.push({ anchor: anchor, level: level, text: text });
    return anchor;
  },
  // 使用堆栈的方式处理嵌套的ul,li,level即ul的嵌套层次,1是最外层
  // <ul>
  //   <li></li>
  //   <ul>
  //     <li></li>
  //   </ul>
  //   <li></li>
  // </ul>
  toHTML: function() {
    let levelStack = [];
    let result = '';
    const addStartUL = () => { result += '<ul>'; };
    const addEndUL = () => { result += '</ul>\n'; };
    const addLI = (anchor, text) => { result += '<li><a href="#'+anchor+'">'+text+'<a></li>\n'; };

    this.toc.forEach(function (item) {
      let levelIndex = levelStack.indexOf(item.level);
      // 没有找到相应level的ul标签,则将li放入新增的ul中
      if (levelIndex === -1) {
        levelStack.unshift(item.level);
        addStartUL();
        addLI(item.anchor, item.text);
      } // 找到了相应level的ul标签,并且在栈顶的位置则直接将li放在此ul下
      else if (levelIndex === 0) {
        addLI(item.anchor, item.text);
      } // 找到了相应level的ul标签,但是不在栈顶位置,需要将之前的所有level出栈并且打上闭合标签,最后新增li
      else {
        while (levelIndex--) {
          levelStack.shift();
          addEndUL();
        }
        addLI(item.anchor, item.text);
      }
    });
    // 如果栈中还有level,全部出栈打上闭合标签
    while(levelStack.length) {
      levelStack.shift();
      addEndUL();
    }
    // 清理先前数据供下次使用
    this.toc = [];
    this.index = 0;
    return result;
  },
  toc: [], 
  index: 0
};

最后的代码实现

post表示文章对象,content是markdown内容,调用marked的时候renderer.heading中就已经往tocObj中写入文章的标题信息了,最后只需要调用一下toHTML就可以产生toc的html代码了。

post2html: function(post) {
  if (post) {
    post.content = marked(post.content);
    post.toc = tocObj.toHTML();
  }
}

锚点定位偏移css

20px是被导航条遮住的高度

.anchor-fix {
    display: block;
    height: 20px; /*same height as header*/
    margin-top: -20px; /*same height as header*/
    visibility: hidden;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你在使用Maven打包时遇到了 JAR will be empty - no content was marked for inclusion! 的错误提示,可能是因为Maven没有正确地识别和打包你的源代码和资源文件。 你可以尝试以下几个解决方案: 1. 确认你的源代码和资源文件在正确的目录下。默认情况下,Maven会将源代码放在src/main/java目录下,资源文件放在src/main/resources目录下。如果你的源代码或资源文件不在这些目录下,你需要在pom.xml文件中配置相应的目录。 2. 确认你在pom.xml文件中正确地配置了Maven打包插件。你需要确保打包插件能够正确地识别和打包你的源代码和资源文件。以下是一个基本的打包插件配置: ``` <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifest> <mainClass>com.example.Main</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> ``` 在该配置中,`<mainClass>` 元素指定了程序的入口类。你需要将该元素替换成你程序的入口类。 3. 如果你的项目使用了其他的打包插件(如maven-assembly-plugin),你需要确保这些插件不会覆盖Maven的默认打包插件。你可以尝试禁用这些插件,或者在pom.xml文件中重新配置它们,以确保能够正确地识别和打包你的源代码和资源文件。 如果以上方法都没有解决问题,你可以尝试清理Maven的本地仓库并重新构建项目,或者使用其他打包方式,如使用IDEA或Eclipse进行打包。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值