原因
:!(彩虹) 在使用 typecho
编辑主题的时候碰到一个问题,就是在文章的页面中如何去自动加上目录链接。
遇到的问题
一开始想到的是找相关的插件作为辅助,但是来回兜了几圈之后发现,别人写的 PHP
插件版本太老了,而且样式也不是很OK不美观,如果是正对源码去修改的话也是很困难的,本人也没学过 PHP
代码,看起来别说多费劲了,边看边猜测。第二个,我也有想到去找一些前端目录的实现,结果也可想而之,不好看也达不到我要的功能。
针对上面的问题,索性我直接从前端手写一个简单的 JS 封装直接调用就好,特此记录这篇供大家参考:
编写目录
在我们的文章中,如果是在编辑器编写的文章带标题的话,是会有 h1, h2, h3...
之类的标签的,类似下图的标签展示,思考一下,我们怎么去拿到文章内的标签呢?这里我选择使用 DOM
节点的遍历。
- 可以先获取到整个文章的内容,然后再拿到内容下所有的节点。
- 拿到节点之后,可以使用
for
循环或者foreach
遍历节点,其中我们遍历是需要条件。 - 遍历的条件是是否包含
h1
,h2
..等之类的节点 ,然后把符合的节点都添加到一个新的数组中保存。 - 再对节点进行第二次的筛选,相当于把第三步获取到的数据再重新排列,因为之前拿到的数据格式是一维数组,这样的格式不是我想要的(设想的格式是,如果有多少类型的标题就创建几维数组),这样后面输出的时候也方便还可以加上我想要的
。 - 接上第四步获取到的结果,使用
for
循环拼接字符串,因为我没有用到VUE
所以直接拼接即可,循环的时候加上索引即可。
具体代码实现
上代码,先获取节点。
// 获取文章内节点(把这个换成你们自己的 id 或者 class )
var content = document.querySelector('.y-detail .content');
// 需要查找的所有节点
var nodes = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'];
// 需要保持的数组
var titles = [];
// 遍历节点内容
content.childNodes.forEach(function (item, index) {
// 当前节点是否包含查找的节点
if (nodes.includes(item.nodeName)) {
// 给查找的节点添加一个 id 标示
var id = "header-" + index;
item.setAttribute("id", id);
// 定义一个节点的等级 1 2,3,4...
var level = Number(item.nodeName.substring(1, 2));
// 定义当前的节点的父节点
var parent = level - 1;
item.level = level;
item.parent = parent;
// 保存到数组中
titles.push({
id: id,
title: item.innerHTML,
level: item.level,
parent: item.parent,
nodeName: item.nodeName,
child: []
})
}
});
里面设置的 ID 是为了在点击的时候获取锚点去滚动到具体文章的具体位置。
第二步为了重新筛选数据。
var map = {};
// 新的存储数组
var roots = [];
// 第一次获取的标签属性(很重要),以这个标签为最大标签,依次获取下级标签
// 如果下级 h 标签比第一次获取的打就不作操作,抛出异常
var firstParent = titles[0] && titles[0].parent;
// 如果没有标签就直接返回,不做操作
if(!firstParent) return
titles.forEach(function(item, index) {
// 把自己的出现的索引保存上
map[item.level] = index
if(item.parent != firstParent) {
// 如果是没找到的情况就跑出异常
if (typeof map[item.parent] !== 'undefined') {
titles[map[item.parent]].child.push(item)
} else {
roots.push({
id: item.id,
title: '目录生成错误,请检查!'
});
}
} else {
roots.push(item)
}
})
最后再把新拿到的数据循环重新拼接到 HTML
中。
具体代码我就不多写了,我把文件放到文章下面,自行下载,然后把里面的代码放到你的页面上,就可以了。
最后呈现结果就如本页面展示的,当然,你得美化一下你的样式。
{anote icon="fa-download" href="https://luszy.com/download/catalogue.zip" type="secondary" content="下载"/}