2 回答
![?](http://img1.sycdn.imooc.com/54584f8f00019fc002200220-100-100.jpg)
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>
![?](http://img1.sycdn.imooc.com/545845d30001ee8a02200220-100-100.jpg)
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
}
})
添加回答
举报