在使用Markdown编辑写文章的时候,我们会使用h1-h6标签来定义章节标题,但是Markdown生成的文章中的h1-h6标签是平行结构,不是树结构,所以我们需要手动去Analyze这些h标签,并根据它们的直接规则生成目录树。文章效果文章dom结构最后生成的目录结构思路获取文章中所有h1~h6标签比较h标签个数,从当前h标签开始判断,如果后面h标签个数比自己大,就会被视为自己的后代。如果h标签的个数小于或等于自己,则立即停止。如果我们得到的h标签是这样的:varhEles=['h4','h6','h3','h4','h4','h1','h2','h3','h3','h3','h3','h2','h3','h3'];然后我们首先需要将它转换成这样:vararr2=[{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}];转换到树:varres=[{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:2children:[{hLevel:3,level:3},{hLevel:3,level:3},{hLevel:3,level:3},{hLevel:3,level:3}]},{hLevel:2,level:2,children:[{hLevel:3,级别:3},{hLevel:3,级别:3}]}]}];1.代码实现方案一functiontoTree(flatArr){vartree=[];varcopyArr=flatArr.map(function(item){returnitem;});//根据指定的level查找本level的子孙,找到的子孙删除vargetChildrenByLevel=function(currentLevelItem,arr,level){if(!currentLevelItem){return;}//将级别值转换为负数,然后比较varminusCurrentLevel=-currentLevelItem.hLevel;变种孩子=[];for(vari=0,len=arr.length;i0){arr.splice(0,children.length);返回孩子;}变种得到ree=function(result,arr,level){//首先移除数组的第一位并将其添加到结果集中varcurrentItem=arr.shift();currentItem.level=level;结果.push(currentItem);while(arr.length>0){if(!currentItem){返回;}//根据当前级别获取其子孙varchildren=getChildrenByLevel(currentItem,arr,level);//如果当前关卡没有子孙,则开始一个if(children.length==0){currentItem=arr.shift();currentItem.level=level;如果(currentItem){result.push(currentItem);}继续;}currentItem.children=[];//找到的子孙继续寻找子孙getTree(currentItem.children,children,level+1);}}getTree(树,copyArr,1);返回树;}测试它:vararr2=[{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));2021年-08-30)函数toTree2(flatArr){varresultArr=[];//结果集数组varstack=[];//堆栈数组flatArr.forEach((levelItem,index)=>{levelItem.children=[];if(resultArr.length==0){//如果第一个循环没有内容,则第一个元素为默认压入栈levelItem.parentCollector=resultArr;//存储父级stack.push(levelItem);resultArr.push(levelItem);}else{letlastestLeveInStack=stack[stack.length-1];//获取栈顶的元素,也就是最近入栈的元素levelItem);lastestLeveInStack.children.push(levelItem);}elseif(lastestLeveInStack.level==levelItem.level){//遇到同级节点levelItem.parentCollector=lastestLeveInStack.parentCollector;stack.push(levelItem);//将当前元素压入栈lastestLeveInStack.parentCollector.push(levelItem);}else{letlastestLeveParentCollector=latestLeveInStack.parentCollector;让lastestLeveParentIndex=stack.findIndex(function(leveItem){returnleveItem.children===latestLeveParentCollector;});if(latestLeveParentIndex>-1){//top节点的父节点letlatestLeveParent=stack[latestLeveParentIndex];if(latestLeveParent.level-1){stack.splice(collectorIndex);}*/stack.push(levelItem);}}}else{console.log('kkkkkkkkkkkkkkk');}}}});//移去元素的parentCollector属性flatArr.forEach(levelItem=>{if(levelItem.parentCollector){deletelevelItem.parentCollector;}if(levelItem.children.length==0){deletelevelItem.children;}});返回结果Arr;}接下来只需要根据树结构生成对应的dom树//根据树结构数据生成章节目录dom树functiongetChapterDomTree(chapterTreeData,parentNode){if(!parentNode){parentNode=createNodeByHtmlStr('')[0];}chapterTreeData.forEach(chapterItem=>{varitemDom=createNodeByHtmlStr(''+chapterItem.text+'')[0];parentNode.appendChild(itemDom);if(chapterItem.children){v??arcatalogList=createNodeByHtmlStr('')[0];itemDom.appendChild(catalogList);getChapterDomTree(chapterItem.children,catalogList);}});returnparentNode;}//根据html字符串生成dom元素functioncreateNodeByHtmlStr(htmlStr){vardiv=document.createElement('div');div.innerHTML=htmlStr;varchildren=div.children;滴v=空;返回孩子;}vartreeData=toTree([...]);vardomTree=getChapterDomTree(treeData);