如何在博客园中自定义博文目录


前言

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

实现过程

js 部分

步骤

  1. 创建一个目录容器 div.catalog,后代结构如下:
    • div.catalog-tab
    • div.catalog-contents
      • div.catalog-title
        • h2
      • a.catalog-close
      • ul
  2. 初始化标题数列表 hNumList = [0, 0, 0, 0, 0, 0],总标题数 hTagNum = 0
  3. 开始遍历以博客正文容器为根节点的 DOM 树的所有节点,当节点为博客标题时,进入步骤4,否则继续循环;
  4. 创建一个 ul 的子标签 li,后代结构如下:
    • a.anchor-link (使用 a 标签的原因是我用了 Silence 主题)
      • span
  5. 判断标题的级别 hLevel,将 hNumList[hLevel]hTagNum 加1,根据 hNumList[:hLevel]生成标题序号 serialNumber,格式为 X.X.X. (X 的个数取决于hLevel );
  6. spanclassName 设置为 'level' + (hLevel + 1),在样式表中会根据 levelX 来设置 margin-left 的值;将 span 和标题名插入 li
  7. 设置 li.namehTagNum ,再根据 li.name 设置 li.onclick
  8. 如果还没遍历所有完节点转入步骤2,否则进入步骤9;
  9. 如果 hTagNum 的值为 0 ,直接返回,否则将 div.catalog 插入 .

代码

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 = `

目录

`; //创建无序列表 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("1024sou_post_body"); };

食用方法

将上述代码插入