Javascript提取文章中的h标签生成文章目录

使用Markdown编辑编写文章时,我们会使用 h1-h6标签来定义章节标题,但Markdown生成的文章中的 h1-h6标签是平行结构的,
并不是一颗树状结构,此时就需要我们手动去解析这些h标签,并根据他们直接的规律生成一目录树
文章效果
Javascript提取文章中的h标签生成文章目录
文章图片

文章dom结构
Javascript提取文章中的h标签生成文章目录
文章图片

最终生成的目录结构
Javascript提取文章中的h标签生成文章目录
文章图片

思路
  1. 获取文章中所有的h1~h6标签
  2. 比较h标签的数字,从当前h标签开始判断,如果后面的h标签数字比自己大则当做自己的子孙级,遇到h标签数字比自己小或和自己一样的则立即停止
假如我们获取到的h标签是这样的:
var hEles = [ 'h4', 'h6', 'h3', 'h4', 'h4', 'h1', 'h2', 'h3', 'h3', 'h3', 'h3', 'h2', 'h3', 'h3' ];

【Javascript提取文章中的h标签生成文章目录】则我们首先需要将其转换成这样:
var arr2 = [ {hLevel: 4}, {hLevel: 6}, {hLevel: 3}, {hLevel: 4}, {hLevel: 4}, {hLevel: 1}, {hLevel: 2}, {hLevel: 3}, {hLevel: 3}, {hLevel: 3}, {hLevel: 3}, {hLevel: 2}, {hLevel: 3}, {hLevel: 3} ];

再转换成树状:
var res = [ { hLevel: 4, level: 1, children: [ {hLevel: 6, level: 2} ] }, { hLevel: 3,, level: 1, children: [ {hLevel: 4, level: 2}, {hLevel: 4, level: 2} ] }, { hLevel: 1, level: 1, children: [ { hLevel: 2, level: 2 children: [ {hLevel: 3, level: 3}, {hLevel: 3, level: 3}, {hLevel: 3, level: 3}, {hLevel: 3, level: 3} ] }, { hLevel: 2, level: 2, children: [ {hLevel: 3, level: 3}, {hLevel: 3, level: 3} ] } ] } ];

代码实现
function toTree(flatArr){ var tree = []; var copyArr = flatArr.map(function (item) { return item; }); // 根据指定级别查找该级别的子孙级,并删除掉已经查找到的子孙级 var getChildrenByLevel = function (currentLevelItem, arr, level) { if(!currentLevelItem){ return; } // 将level值转成负数,再进行比较 var minusCurrentLevel = -currentLevelItem.hLevel; var children = []; for(var i = 0, len = arr.length; i < len; i++){ var levelItem = arr[i]; if(-levelItem.hLevel < minusCurrentLevel){ children.push(levelItem); }else { // 只找最近那些子孙级 break; } } // 从数组中删除已经找到的那些子孙级,以免影响到其他子孙级的查找 if(children.length > 0){ arr.splice(0, children.length); } return children; }var getTree = function (result, arr, level) { // 首先将数组第一位移除掉,并添加到结果集中 var currentItem = arr.shift(); currentItem.level = level; result.push(currentItem); while (arr.length > 0){ if(!currentItem){ return; } // 根据当前级别获取它的子孙级 var children = getChildrenByLevel(currentItem, arr, level); // 如果当前级别没有子孙级则开始下一个 if(children.length == 0){ currentItem = arr.shift(); currentItem.level = level; if(currentItem){ result.push(currentItem); } continue; } currentItem.children = []; // 查找到的子孙级继续查找子孙级 getTree(currentItem.children, children, level + 1); } } getTree(tree, copyArr, 1); return tree; }

测试一下:
var arr2 = [ {hLevel: 4}, {hLevel: 6}, {hLevel: 3}, {hLevel: 4}, {hLevel: 4}, {hLevel: 1}, {hLevel: 2}, {hLevel: 3}, {hLevel: 3}, {hLevel: 3}, {hLevel: 3}, {hLevel: 2}, {hLevel: 3}, {hLevel: 3} ]; console.log(toTree(arr));

Javascript提取文章中的h标签生成文章目录
文章图片

接下来只需要根据这个树状结构生成对应的dom树就可以了
// 根据树状结构数据生成章节目录dom树 function getChapterDomTree(chapterTreeData, parentNode){ if(!parentNode){ parentNode = createNodeByHtmlStr('
    ')[0]; } chapterTreeData.forEach(chapterItem => { var itemDom = createNodeByHtmlStr('
  • ' + chapterItem.text + '
  • ')[0]; parentNode.appendChild(itemDom); if(chapterItem.children){ var catalogList = createNodeByHtmlStr('
      ')[0]; itemDom.appendChild(catalogList); getChapterDomTree(chapterItem.children, catalogList); } }); return parentNode; }// 根据html字符串生成dom元素 function createNodeByHtmlStr(htmlStr){ var div = document.createElement('div'); div.innerHTML = htmlStr; var children = div.children; div = null; return children; }var treeData = https://www.it610.com/article/toTree([...]); var domTree = getChapterDomTree(treeData);

        推荐阅读