欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

js压缩代码后怎么生成source map_??markdown生成导航? #x27;[toc]#x27;足矣

发布时间:2024/9/19 编程问答 46 豆豆
生活随笔 收集整理的这篇文章主要介绍了 js压缩代码后怎么生成source map_??markdown生成导航? #x27;[toc]#x27;足矣 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

快速食用地址:https://github.com/ahungrynoob/showdown-toc

背景

什么是toc? table of contents 是markdown中的导航信息,能够通过heading和锚点快速定位。

最近在开发个人博客的时候,希望有一个生成目录导航的功能,目的是做一个像语雀右上角一样的导航栏:


使用的markdown渲染引擎是showdown,找了半天,只找到一个jquery写的toc插件,也不支持nodejs。(很好,又是一个造轮子,开源,刷福报的好机会!)
于是就自己做了一个插件,支持两大功能:

  • 会把文章中所有的heading信息,通过闭包的形式传达到上层域
  • markdown中写[toc],即可生成toc到markdown的相应位置中。
  • 效果:

    使用前:

    使用后:

    开发过程

    汲取和熟悉

    首先阅读showdown的wiki,了解extension机制和写法。了解到以下几点:

  • extension 分为 lang 和 output两种
  • lang 的extension会在markdown一开始的时候(normalize之后)就执行,output会在最后执行。
  • 作者还很热心的指出了一些坑(递归调用,不要修改converter):https://github.com/showdownjs/showdown/wiki/extensions#filter-property
  • 思路

    老的思路:自己写一个lang插件,在一开始引擎读md的时候,就去收集信息,结果证明:❌
    原因: 实践过程中,showdown有缓存机制,只会读取一遍md内容,之后读的都是html的内容,就无法收集toc的元信息了。

    新思路:在output阶段中解析html的h1到h6标签,收集heading信息,并替代[toc]的占位符,输出到html中,结果证明:✅

    步骤以及代码:

    整个代码的核心是这个正则:/(<h([1-6]).*?id="([^"]*?)".*?>(.+?)</h[1-6]>)|(<p>[toc]</p>)/g;
    这个正则,获取了h1-h6的标题信息以及toc的占位符的位置和次数

    第一步:

    在这里,showdown-toc会去寻找并按出现次序收集tocItem和[toc]

    // find and collect all headers and [toc] node;const collection: MetaInfo[] = [];source.replace(regex, (wholeMatch, _, level, anchor, text) => {if (wholeMatch === '<p>[toc]</p>') {collection.push({ type: 'toc' });} else {text = text.replace(/<[^>]+>/g, '');const tocItem = {anchor,level: Number(level),text,};// 如果传了闭包的数组参数toc,就会把标题信息推入if (toc) {toc.push(tocItem);}collection.push({type: 'header',...tocItem,});}return '';});

    tocItem长这样:

    type TocItem = {anchor: string; // 锚点level: number; // 标题级别text: string; // 标题内容 };

    第二步

    这里,出现[toc]之后,会收集这个[toc]到下个[toc]之间的标题信息

    // calculate toc infoconst tocCollection: TocItem[][] = [];collection.forEach(({ type }, index) => {if (type === 'toc') {if (collection[index + 1] && collection[index + 1].type === 'header') {const headers = [];const { level: levelToToc } = collection[index + 1] as TocItem;for (let i = index + 1; i < collection.length; i++) {if (collection[i].type === 'toc') break;const { level } = collection[i] as TocItem;if (level === levelToToc) {headers.push(collection[i] as TocItem);}}tocCollection.push(headers);} else {tocCollection.push([]);}}});

    第三步:

    这个阶段,会把source中的showdown给我们生成的<p>[toc]</p>标签替换成我们生成toc标签,也就是ol和li标签啦。然后把处理后的source返回给showdown就好了。整个插件也就完成了。

    // replace [toc] node in sourcesource = source.replace(/<p>[toc]</p>[n]*/g, () => {const headers = tocCollection.shift();if (headers && headers.length) {const str = `<ol>${headers.map(({ text, anchor }) => `<li><a href="#${anchor}">${text}</a></li>`).join('')}</ol>n`;return str;}return '';});

    总结

    整个插件很简单,但是中间也遇到了不少坑,出现过思路的碰撞。实现的主要步骤逻辑如下:

  • 寻找和收集h1-h6以及[toc]的出现次数和次序
  • 计算两次[toc]之间的标题
  • 用我们自己生成toc标签去替换<p>[toc]</p>占位标签,输出成html字符串。
  • 欢迎pr

    项目地址:https://github.com/ahungrynoob/showdown-toc

    总结

    以上是生活随笔为你收集整理的js压缩代码后怎么生成source map_??markdown生成导航? #x27;[toc]#x27;足矣的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。