关于javascript:Javascript提取文章中的h标签生成文章目录

36次阅读

共计 2915 个字符,预计需要花费 8 分钟才能阅读完成。

应用 Markdown 编辑编写文章时,咱们会应用 h1-h6 标签来定义章节题目,但 Markdown 生成的文章中的 h1-h6 标签是平行结构的,
并不是一颗树状构造,此时就须要咱们手动去解析这些 h 标签,并依据他们间接的法则生成一目录树

文章成果

文章 dom 构造

最终生成的目录构造

思路

  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'
];

则咱们首先须要将其转换成这样:

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));

接下来只须要依据这个树状构造生成对应的 dom 树就能够了

// 依据树状构造数据生成章节目录 dom 树
function getChapterDomTree(chapterTreeData, parentNode){if(!parentNode){parentNode = createNodeByHtmlStr('<ul class="markdown-toc-list"></ul>')[0];
  }
  chapterTreeData.forEach(chapterItem => {var itemDom = createNodeByHtmlStr('<li><a class="toc-level-'+ chapterItem.level +'" href="#' + chapterItem.id + '">' + chapterItem.text + '</a></li>')[0];
    parentNode.appendChild(itemDom);
    if(chapterItem.children){var catalogList = createNodeByHtmlStr('<ul class="markdown-toc-list"></ul>')[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 = toTree([...]);
var domTree = getChapterDomTree(treeData);

正文完
 0