至于为什么是,二,当然是因为当年年少
很久以前写过一篇 使用 JavaScript 生成一个简单文章目录,还大言不惭的说很简单,于是才有了这个拖了四年的 BUG。
之前只做了简单层级拼接,两层就没问题,在稍微复杂时便错乱了,当时水平也一般,看不出端倪。
理论上这是一个需要多次递归处理的类似树型结构的问题,修复完成后的代码更多也更长,直接上代码:
/**
* 节点类
* menu 为节点 element
* parent 为父节点
* child 为子节点
* 例:
* h2-1
* h3-1
* h4-1
* h2-2
* h3-2
*/
class Node {
constructor(menu, parent = null) {
this.menu = menu;
this.parent = parent;
this.child = [];
}
//节点层级
level() {
return levelNum(this.menu.id);
}
//添加子节点
add(node) {
this.child.push(node);
}
//寻找同级节点的父节点
findParent(level) {
if (this.level() === level) {
return this.parent;
} else {
return this.child.length === 0
? this
: this.child[this.child.length - 1].findParent(level);
}
}
toString() {
return this.menu + JSON.stringify(this.child);
}
}
//增加 html 锚点,格式:h2-num ,比如:h2-1、h3-1
function add_tag(container, tag) {
for (let i = 0; i < container.length; i++) {
container[i].id = tag + "-" + (i + 1);
container[i].className = "j-menu";
}
}
//判断 锚点 层级,取锚点 h2-1 前两位 h2 的后一位 2,越大则层级越深
function levelNum(tag) {
return tag.toString().substring(1, 2);
}
//获取整个文章结构 进行 tag 标记(不限于 h2 h3 h4)
var tags = ["h2", "h3", "h4"];
for (t = 0; t < tags.length; t++) {
var container = document.querySelectorAll(".article_content > " + tags[t]);
add_tag(container, tags[t]);
}
var menuDom = [];
menuDom[0] =
'<h3 class="uk-h5">文章结构</h3><ul class="uk-nav uk-nav-default">';
let menus = document.querySelectorAll(".j-menu");
//定义节点列表
const nodes = [];
//上次使用的父节点
let lastNode;
menus.forEach((menu) => {
const level = levelNum(menu.id);
if (nodes.length === 0) {
//初始化节点列表
nodes.push(new Node(menu));
lastNode = nodes[nodes.length - 1];
return;
}
//上一次的层级
const lastLevel = lastNode.level();
//尝试在上一个父节点中寻找相同层级 并返回父节点
const parent = lastNode.findParent(level);
if (lastLevel === level) {
if (!parent) {
//层级相同 父节点为空 顶层节点
const element = new Node(menu);
nodes.push(element);
lastNode = element;
} else {
//层级相同 有父节点则直接使用
parent.add(new Node(menu, parent));
lastNode = parent;
}
} else {
if (!parent || parent.level() > level) {
//层级不同 父节点为空 或者 父节点的层级已经大于当前节点 比如 h3-3/h4-3 切换到 h2-2 时
const element = new Node(menu);
nodes.push(element);
lastNode = element;
} else {
//层级不同 但能找到有父节点 直接使用
lastNode = parent;
parent.add(new Node(menu, parent));
}
}
});
//递归构建菜单 html
function handleDom(child) {
child.forEach((node) => {
let menu = node.menu;
var content = '<a href="#' + menu.id + '">' + menu.innerText + "</a>";
if (node.child.length > 0) {
menuDom[menuDom.length + 1] =
'<li class="uk-parent">' + content + '<ul class="uk-nav-sub">';
handleDom(node.child);
menuDom[menuDom.length + 1] = "</ul></li>";
} else {
var subfix = "<li>" + content + "</li>";
menuDom[menuDom.length + 1] = subfix;
}
});
}
handleDom(nodes);
//完成最后一笔
menuDom[menuDom.length + 1] = "</ul>";
// console.log(menuDom.join(""));
if (menus.length >= 1) {
document.getElementById("menu-container").innerHTML = menuDom.join("");
} else {
document.getElementById("menu-container").innerHTML =
"<div class='uk-nav-h5 uk-margin-large-top'>不好意思噢, 没有在这篇文章中找到目录。</div>";
}
想理解逻辑就自行 debug 吧,当然里面还留了一个 BUG,如果你的文章目录有十几层,可以到 H11,那么这句就不对了:
tag.toString().substring(1, 2);
文件可直接在本站网页资源上获取,算法的一部分看似可以合并,实际上无法合并,不是专业写 JS 的,能用就行。
以上。
本站由以下主机服务商提供服务支持:
0条评论