资讯专栏INFORMATION COLUMN

JavaScript生成TOC

chinafgj / 2201人阅读

摘要:本人为菜鸟,有问题请指正目录最近用搭建个人博客在制作文章显示页面时,需要在前端页面生成。刚开始很纠结如何生成有层级结构的代码,最后发现可以使用设计模式中的组合模式来完成这一功能。具体点就是将节点看作叶子节点,节点看错作容器。

本人为Javascript菜鸟,有问题请指正...

TOC目录

最近用Flask搭建个人博客在制作文章显示页面时,需要在前端页面生成TOC。就打算自己写一个JavaScript脚本。

需要生成的目标HTML代码如下:

    

在看了JavaScript权威指南这本书后,发现其中虽然有例子生成TOC,但是并没有显示层级。不过,其中有一个记录TOC各个锚点序号的好方法:

# 使用一个数组报错的level为1
var level = parseInt(header.tagName.charAt(1));
# 当处理一个标签后,计算加1
sectionNumbers[level-1]++
# 然后去当前序号 比如序号为2.1.1
sectionNumber = sectionNumbers.slice(0,level).join(".")
分析算法逻辑

吹牛B之前需要打草稿,写代码之前也如此。

刚开始很纠结如何生成有层级结构的HTML代码,最后发现可以使用设计模式中的组合模式来完成这一功能。具体点就是将li节点看作叶子节点,ul节点看错作容器。那么就有一下限制:

只有ul节点可以插入li节点

li节点需要插入子节点,就需要创建一个ul子节点,让子节点去插入li节点

ul与它的li子节点level相同

如果当前节点需要处理一个header,就需要作出以下判断:

判断自己为ul节点还是li节点

如果为ul节点,且待处理的header的level与自己相同,那么就直接生成一个li节点并插入;如果待处理的header的level比自己大,那么就找到子节点,交给子节点去处理。

如果为li节点,且待处理的header的level比自己大,那么就取li节点的ul节点,交给ul节点去处理

一直向下去处理header,直到插入成功

代码实现

为了尽量减少代码的污染,使用Fucntion.call(args)方式了动态的给节点添加属性:

var sectionNumbers = [0, 0, 0, 0, 0, 0];

function Toc() {
    this.headers = $(this).find(":header");
    var ul = document.createElement("ul");
    this.toc = TocObj.call(ul, 1);
    for(var i = 0; i < this.headers.length; i++) {
        // if(i > 1) break;
        this.toc.add(this.headers[i]);
    }
    console.log(this.toc);
}

function TocObj(level) {
    this.level = level;
    this.num = 0;
    this.add = function(header) {
        var flag = this.tagName == "UL"; // ul节点和li节点处理header的方式不通过
        var level = parseInt(header.tagName.charAt(1));
        if(flag) { // 只有ul节点才能插入li
            if(this.num == 0 || level == this.level) {
                var link = document.createElement("a");
                link.href = "";
                link.innerHTML = header.innerHTML;
                sectionNumbers[level-1]++;
                for(var i = level; i < sectionNumbers.length; i++) sectionNumbers[i] = 0;
                link.href = "#TOC" + sectionNumbers.slice(0, level).join(".");
                var li = document.createElement("li");
                li.insertBefore(link, li.firstChild);
                this.num++;
                this.appendChild(TocObj.call(li, level));
            } else if(level > this.level){
                if(this.num == 0) { 
                    throw new Error("level error 1");  
                }
                var lastChild = this.lastChild;
                lastChild.add(header); // 让ul节点的li节点去处理header
            }
        } else { // li节点让它的ul子节点去插入li
            if(level == this.level) {
                throw new Error("level error 2");
            } else if(level > this.level){ 
                if(this.num == 0) { // 没有ul子节点,就创建一个
                    var ul = document.createElement("ul");
                    this.appendChild(ul);
                    this.num++;
                    TocObj.call(ul, level).add(header); // 注意设置level
                } else { 
                    var lastChild = this.lastChild;
                    lastChild.add(header); //让ul节点去处理这个header
                }
            }
        }
    }
    return this;
}

var toc = document.getElementsByClassName("post")[0];
Toc.call(toc);
效果展示

对于有以下结构的HTML代码:

标题1

标题1.1

标题1.2

标题2

标题2.1

标题2.1.1

标题3

标题4

标题5

输出结构如下:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87713.html

相关文章

  • 为你的文章生成目录索引

    摘要:使用可以快速为你的页面生成目录的结构,拥有较强的可定制性,并且并不会擅自为你做太多的事情,以便你更容易地把应用到你的项目中。 引言 为页面中的标题元素建立目录索引,这是一个不起眼却很实用的功能,特别是对于那些含有篇幅很长的文章的页面,拥有一个目录可以让读者对文章的结构一目了然,更重要的是,读者可以很轻松地在文章的各个章节之间来回快速跳转,极大地提高了用户体验。 toc.js 使用 to...

    魏宪会 评论0 收藏0
  • JavaScript Style Guide

    摘要:在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。分号语句结束一定要加分号类型转换在语句的开始执行类型转换字符串对数字使用并且总是带上类型转换的基数布尔值命名约定避免单个字符名,让你的变量名有描述意义。 原文:https://github.com/airbnb/javascript JavaScript规范 内容列表 类型 对象 数组 字符串 函数 属性 变量 条件表达式和等号...

    habren 评论0 收藏0
  • 导出 VuePress 构建的网站为 PDF

    摘要:文章首发自我的个人网站前言学也有一段时间了网上也有不少官方文档的中文翻译版但是似乎只有中文网站文档一直是最新的奈何并没有供直接下载是在是不太方便为了方便阅读以及方便后续文档更新决定用写一个爬虫将网页下载下来保持为最后完成结果如下是的没错 文章首发自我的 个人网站-Leetaos Blog 前言 学 Rust 也有一段时间了,网上也有不少官方文档的中文翻译版,但是似乎只有 [Rust中...

    AlphaWallet 评论0 收藏0
  • cheerio制作markDown索引目录

    摘要:原文链接的博客制作目录索引这种东西当然是放在前端方便。选择放在后端一是为了了解后端生态,掌握更多后端技术二是因为公司实行前后端分离的方式开发,睾贵的后端经常啥也不做处理就返回一个数据甚至有时时间戳都不处理,对此有些无语。 原文链接:Bougie的博客 制作目录索引这种东西当然是放在前端方便。选择放在后端一是为了了解Node后端生态,掌握更多后端技术;二是因为公司实行前后端分离的方式开发...

    wanglu1209 评论0 收藏0
  • 为 github markdown 文件生成目录

    摘要:文件一键生成目录支持优雅的写法支持多次生成支持重复标题的生成支持特殊字符的过滤支持指定不同的文件编码支持文件夹的文件批量处理可指定是否包含子文件夹文件支持是否写入文件,可返回目录的内容,便于用户自行处理环境依赖请确保设置正确。 业务需要 在编写 github 项目时,有时候会编写各种 README.md 等 markdown 文件,但是 github 默认是没有目录的。 于是就自己想办...

    Mr_houzi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<