正在加载中...

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

前言

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

实现过程

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 插入 <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(/&nbsp;/ig, ""); //替换掉所有的&nbsp;
                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;
}

写在最后

在博客园中自定义博文目录的方法就介绍到这里了,大家可以根据自己的需求随意魔改。如果你喜欢这篇博客或者博客对你有帮助的话,不要忘记点击右下角的推荐按钮哦~~

posted @ 2021-04-12 10:54  之一Yo  阅读(331)  评论(2编辑  收藏  举报