如何在博客园中自定义博文目录
前言
当博客很长时,目录的大纲作用就凸显出来了。但是对于目录,还是希望能简洁一些,不能在页面中占太大空间,避免产生阅读干扰。所以下面我们来实现一个简洁明了的博文目录,效果如下:

实现过程
js 部分
步骤
- 创建一个目录容器
div.catalog
,后代结构如下:div.catalog-tab
div.catalog-contents
div.catalog-title
h2
a.catalog-close
ul
- 初始化标题数列表
hNumList = [0, 0, 0, 0, 0, 0]
,总标题数hTagNum = 0
; - 开始遍历以博客正文容器为根节点的 DOM 树的所有节点,当节点为博客标题时,进入步骤4,否则继续循环;
- 创建一个
ul
的子标签li
,后代结构如下:a.anchor-link
(使用a
标签的原因是我用了 Silence 主题)span
- 判断标题的级别
hLevel
,将hNumList[hLevel]
和hTagNum
加1,根据hNumList[:hLevel]
生成标题序号serialNumber
,格式为X.X.X.
(X 的个数取决于hLevel
); - 将
span
的className
设置为'level' + (hLevel + 1)
,在样式表中会根据levelX
来设置margin-left
的值;将span
和标题名插入li
; - 设置
li.name
为hTagNum
,再根据li.name
设置li.onclick
; - 如果还没遍历所有完节点转入步骤2,否则进入步骤9;
- 如果
hTagNum
的值为0
,直接返回,否则将div.catalog
插入<body>
.
代码
复制var BlogCatalog = {
/**
*创建博客目录,支持六级标题
* @param {string} id 包含博文正文的 div 容器的 id
*/
createCatalog(id) {
//获取博文正文div容器
var elem = document.getElementById(id);
if (!elem) return false;
//获取div中所有元素结点
var nodes = elem.getElementsByTagName("*");
//创建博客目录的容器
var catalog = document.createElement('div');
catalog.className = 'catalog';
catalog.innerHTML = `<div class='catalog-tab' style='display: block;'>
<h2>目录</h2>
</div>
<div class='catalog-contents' style='display: none;'>
<div class='catalog-title'>
<h2>目录</h2>
</div>
<a class='catalog-close'>✕</a>
<ul></ul>
</div>`;
//创建无序列表
var ul = catalog.getElementsByTagName('ul')[0];
var hTagNum = 0;
var hTagList = ["H1", 'H2', 'H3', 'H4', 'H5', 'H6'];
//遍历所有元素结点
var lastHLevel = 0;
var hNumList = [0, 0, 0, 0, 0, 0];
for (var i = 0, len = nodes.length; i < len; i++) {
var hLevel = hTagList.indexOf(nodes[i].nodeName);
if (hLevel != -1) {
//获取标题文本
var titleText = nodes[i].innerHTML.replace(/<\/?[^>]+>/g, "");
titleText = titleText.replace(/ /ig, ""); //替换掉所有的
titleText = BlogCatalog.htmlDecode(titleText);
//插入锚
nodes[i].setAttribute("id", "blogTitle" + hTagNum);
var li = document.createElement('li');
li.className = 'li_h' + (hLevel + 1);
hNumList[hLevel]++;
if (lastHLevel < hLevel) {
//遇到子标题
lastHLevel = hLevel;
} else if (lastHLevel > hLevel) {
//从子标题返回上一级标题
hNumList.fill(0, hLevel + 1);
lastHLevel = hLevel;
}
//获取序号
var serialNumber = hNumList.slice(0, hLevel + 1).join('.') + '.';
//创建标签
var a = document.createElement('a');
var span = document.createElement('span');
span.className = 'level' + (hLevel + 1);
span.innerText = serialNumber + ' ';
a.appendChild(span);
a.appendChild(document.createTextNode(titleText));
li.appendChild(a);
//创建锚链接
li.setAttribute("name", hTagNum);
li.onclick = function () {
var title = document.getElementById("blogTitle" + this.getAttribute("name"));
title.scrollIntoView({ behavior: 'smooth' });
};
//将列表项添加到无序列表中
ul.appendChild(li);
hTagNum++;
}
}
if (hTagNum == 0) return false;
/*事件处理*/
var catalogTab = catalog.getElementsByClassName('catalog-tab')[0];
var catalogContents = catalog.getElementsByClassName('catalog-contents')[0];
catalogTab.onclick = function () {
catalogTab.style.display = 'none';
catalogContents.style.display = 'block';
};
catalog.getElementsByClassName('catalog-close')[0].onclick = function () {
catalogContents.style.display = 'none';
catalogTab.style.display = 'block';
};
document.body.appendChild(catalog);
},
htmlDecode(text) {
var div = document.createElement("div");
div.innerHTML = text;
var output = div.innerText || div.textContent;
div = null;
return output;
},
};
window.onload = function () {
BlogCatalog.createCatalog("cnblogs_post_body");
};
食用方法
将上述代码插入 <script>
标签中,再将 <script>
标签添加入 设置 -> 博客侧边栏公告 中,前提是已经申请到了博客园的 js 权限
css 部分
将以下代码插入 设置 -> 页面定制 CSS 代码 中(样式表中没有设置 li:hover
,因为我使用了 Silence 主题,a:hover
已经被设置为主题色了),点击保存:
复制.catalog {
position: fixed;
top: 120px;
right: 1px;
width: auto;
height: auto;
background-color: transparent;
z-index: 999999;
font-size: 14px;
border: 1px solid transparent;
border-radius: 1px;
}
.catalog-tab {
cursor: pointer;
display: none;
padding: 7px 2px 7px 2px;
float: right;
width: 25px;
color: #314659;
border: 1px solid #eef2f8;
font-size: 14px;
border-radius: 3px;
text-align: center;
background-color: #fff;
box-shadow: 0 1px 3px rgb(18 18 18 / 10%)
}
.catalog-contents {
overflow: hidden;
display: none;
color: #314659;
border: 1px solid #eef2f8;
border-radius: 3px;
min-width: 150px;
opacity: 1;
font-size: inherit;
background-color: #fff;
z-index: 19941112;
box-shadow: 0 1px 20px 0 rgb(0 0 0 / 10%)
}
.catalog-title {
padding-left: 12px;
width: 100%;
height: 35px;
line-height: 36px;
border-bottom: 1px solid #eef2f8;
font-size: 14px;
color: #314659;
overflow: hidden;
}
.catalog-close {
position: absolute;
right: 15px;
top: 10px;
cursor: pointer;
text-decoration: none;
}
.catalog-contents ul {
padding: 10px 15px;
max-height: 350px;
overflow-y: auto;
}
.catalog-contents ul li {
margin-top: 5px;
max-width: 170px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
.catalog-contents ul li a {
font-size: 13px;
}
.catalog-contents ul li .level1 {
margin-left: 0;
}
.catalog-contents ul li .level2 {
margin-left: 10px;
}
.catalog-contents ul li .level3 {
margin-left: 20px;
}
.catalog-contents ul li .level4 {
margin-left: 30px;
}
.catalog-contents ul li .level5 {
margin-left: 40px;
}
.catalog-contents ul li .level6 {
margin-left: 50px;
}
写在最后
在博客园中自定义博文目录的方法就介绍到这里了,大家可以根据自己的需求随意魔改。如果你喜欢这篇博客或者博客对你有帮助的话,不要忘记点击右下角的推荐按钮哦~~
分类:
Javascript
标签:
css
, javascript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通