为了账号安全,请及时绑定邮箱和手机立即绑定

如何从 DOM 以相同顺序创建标题标签的嵌套列表元素

如何从 DOM 以相同顺序创建标题标签的嵌套列表元素

人到中年有点甜 2022-12-18 16:09:05
所以我有一个 HTML 文档,其中包含任意数量的 h1、h2、h3、h4 等标签,带有嵌套。例子。<h2>About cats</h2><p>Some Info about cats</p><h2>About dogs</h2><p>Some Info about cats</p><h3>Breed 1</h3><p>About breed 1</p><h3>Breed 2</h3><p>About breed 2</p><h2>About birds</h2><p>Info about birds</p>现在,我想要的是,进行一些 DOM 遍历,获取所有标题标签,id通过将它们的内容设为蛇形大小写来为它们添加属性<h2 id="about-dogs" >About Dogs</h2>然后,创建一个包含以下内容的列表元素。嵌套将根据标题标签的位置和位置进行。意味着每个标题将嵌套在第一个更高级别的标题中,依此类推。因此,如果只有一个h1,那么它将形成一棵树,h1其根为根,最低级别的标题为叶。<ul>   <li><a href="#about-cats" >About cats</a></li>   <li><a href="#about-dogs">About dogs</a></li>      <ul>        <li><a href='#breed-1' >Breed 1</a></li>        <li><a href='#breed-2' >Breed 1</a></li>      </ul>    <li><a href='#about-birds' >About birds</a></li></ul>
查看完整描述

2 回答

?
一只名叫tom的猫

TA贡献1906条经验 获得超3个赞

演示

function getHeaders() {

  const hTags = ["h1", "h2", "h3", "h4", "h5", "h6"];

  const elements = document.querySelectorAll(hTags.join());

  const headers = [];


  elements.forEach(el => {

    const text = el.innerText;

    const id = text

      .toLowerCase()

      .split(" ")

      .join("-");


    el.setAttribute("id", id);


    headers.push({

      id,

      text,

      level: hTags.indexOf(el.tagName.toLowerCase())

    });

  });


  return headers;

}


function buildTree(headers) {

  const list = [];

  let nextLevelHeaders = [];

  let lastLevel = -1;


  if (headers.length === 0) {

    return "";

  }


  const buildSubTree = () => {

    if (nextLevelHeaders.length > 0) {

      list[list.length - 1] += buildTree(nextLevelHeaders);

    }

  };


  headers.forEach(h => {

    if (lastLevel !== -1 && lastLevel < h.level) {

      nextLevelHeaders.push(h);

      return;

    }


    buildSubTree();


    lastLevel = h.level;

    list.push(`<a href="#${h.id}">${h.text}</a>`);

    nextLevelHeaders = [];

  });


  buildSubTree();


  const listHTML = list.map(i => `<li>${i}</li>`).join("");

  return `<ul>${listHTML}</ul>`;

}


const headers = getHeaders();


document.querySelector("#root").innerHTML = buildTree(headers);

<div id="root"></div>


<h3>About horses (h3)</h3> <!-- corner case -->

<p>Some Info about horses</p>


<h2>About cats (h2)</h2>

<p>Some Info about cats</p>


<h2>About dogs (h2)</h2>

<p>Some Info about cats</p>

<h3>Breed 1 (h3)</h3>

<p>About breed 1</p>

<h3>Breed 2 (h3)</h3>

<p>About breed 2</p>

<h4>Breed 2.1 (h4)</h4>

<p>About breed 2.1</p>

<h4>Breed 2.2 (h4)</h4>

<p>About breed 2.2</p>

<h3>Breed 3 (h3)</h3>

<p>About breed 3</p>

<h3>Breed 4 (h3)</h3>

<p>About breed 4</p>


<h2>About birds (h2)</h2>

<p>Info about birds</p>


<h4>Bird <b>one</b> (h4)</h4><!-- corner case -->

<p>Info about birds</p>


查看完整回答
反对 回复 2022-12-18
?
青春有我

TA贡献1784条经验 获得超8个赞

好的,我认为我们可以做得更好,但是现在,这段代码可以满足您的期望,前提是您的 html 中有一个带有id="list"的元素可以将您的列表放入


在 Codepen 上查看实际效果


<nav id="list">

</nav>

let headers = document.querySelectorAll('h1, h2, h3')


let list = document.createElement('ul')

document.querySelector('#list')

  .appendChild(list)

  // list is now a ul in the nav section


let currentListLevel = 0

let currentListUl = list

let lastListItem = list

headers.forEach(h => {

  let text = h.innerText

  let level = h.tagName.slice(-1)

  console.log(level + ':' + text)

  let snakeCase = text.toLowerCase()

    .trim()

    .replace(' ', '-')

  

  h.id = snakeCase // now title has id

  

  let link = document.createElement('a')

  // create the link

  link.appendChild(document.createTextNode(text))

  // give it the text of the header

  link.href = '#' + snakeCase

  // give it the reference to the header

  let li = document.createElement('li')

  li.appendChild(link)

  

  if (level === currentListLevel) {

    currentListUl.appendChild(li)

    lastListItem = li

  } else if (level > currentListLevel) {

    currentListLevel = level

    let ul = document.createElement('ul')

    ul.level = level // store the level in a property

    ul.appendChild(li)

    lastListItem.appendChild(ul)

    currentListUl = ul

    lastListItem = li

  } else if (level < currentListLevel) {

    while (level < currentListLevel) {

      currentListUl = currentListUl.parentNode

      level = currentListUl.level

    }

    currentListUl.appendChild(li)

    lastListItem = li

    currentListLevel = level

  }

  

})


查看完整回答
反对 回复 2022-12-18
  • 2 回答
  • 0 关注
  • 82 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信