个人博客网站文章添加目录导航
文章出自个人博客https://knightyun.github.io/2020/01/14/website-add-category,转载请申明
概述
之前有写文章探索如何给个人博客网站添加文章搜索功能,可以方便的通过关键词检索相关文章,现在再来探索一下另一个功能,即给文章添加目录导航;对于篇幅较短的文章,目录的有无影响不大,但是当文章篇幅过长时,一个能提供预览和跳转的目录结构预览,就显得意义重大了,接下来就来一步步将它实现出来;
原理
样式
实现功能必先思考其原理,目录预览其实就是一块内容,包含当前页面不同级别的标题的组合,并结构化的展示出来,首先我们可以参考一些网站的做法,比如 CSDN 的博客文章就有配置目录插件,下面就是我的某篇文章的目录预览图:
它们的目录插件就是右边侧栏的一个按钮,鼠标放上去就会显示一个侧栏,内容就是当前文章的小标题的集合,不同级别的标题对应这不同程度的缩进,并且点击每个标题都会有相应的页面跳转,这也基本是我们常见而熟悉的目录形式,那么我们就以此为参考来实现;
目录获取
想要生成这么一个目录之前,当然是要先获取目录的内容,前面讲过,目录的内容就是当前文章的所有标题的集合,而我们知道,在 HTML 中标题相关的标签是 h1, h2, h3, h4, h5, h6
这几个,所以直接获取它们就行了,比如:
// 获取所有的标签名为 h1 的元素
document.querySelectorAll('h1');
// 获取所有的标签名为 h1 - h6 的元素
document.querySelectorAll('h1, h2, h3, h4, h5, h6');
获取内容是一个数组,包含所有标题节点;接下来的问题就是考虑如何结构化存储,这样便于理解的同时又方便后期的读取,所谓结构化,即目录本身就是一类 树 结构,比如,目录包含多个一级标题,同时某些以及标题可能还有多个二级标题,甚至再向下延伸出三级标题等等,类似下面的结构:
├─ 一级标题 1
│ └─ 二级标题 1
│ └─ 三级标题 1
│ └─ 四级标题
├─ 一级标题 2
│ └─ 二级标题 1
├─ 一级标题 3
│ ├─ 二级标题 1
│ ├─ 二级标题 2
│ ├─ 二级标题 3
│ │ ├─ 三级标题 1
│ │ ├─ 三级标题 2
... ...
理论的做法就是以树结构保存获取的标题,类似于下面这种:
[{node: 'h1Node', // 一级标题 1 对应的节点child: [{node: 'h2Node', // 二级标题 1child: [{node: 'h3Node', // 三级标题 1child: []}]},{node: 'h2Node', // 二级标题 2child: []}]
},
{node: 'h1Node', // 一级标题 2child: [{node: 'h2Node', // 二级标题 1child: []}]
},
{node: 'h1Node', // 一级标题 3child: []
}]
看着还是比较复杂的,耗费的空间也较大,需要递归式获取,最后也要递归式的输出,一般文章目录包含的标题数量也是较少的,所以暂且不用这种结构来保存,可以换一种简单的思路,即我们最后生成该目录时可以选择一行一行递进的输出,即设计如下结构:
['h1Node', // 一级标题 1 对应的元素节点'h2Node', // 二级标题 1 (隶属于一级标题 1)'h3Node', // 三级标题 1 (隶属于二级标题 1)'h2Node', // 二级标题 2 (隶属于一级标题 1)'h1Node', // 一级标题 2'h2Node', // 二级标题 1 (隶属于一级标题 2)'h1Node' // 一级标题 3
]
因为我们只要求最终能输出一列格式化的目录,即挨个依次输出,所以只需以此存储即可,这样占用的空间和复杂度都有所减少;
目录生成
最终展示效果设定为最上面的样图所示,按照之前设计的存储结构,遍历该数组一行一行打印出来即可;关于不用级别的标题应用不同程度的缩进,可以巧妙利用一下元素节点的 nodeName
这个属性,比如元素节点 <h1></h1>
对应的 nodeName
就是 H1
,h2
就对应 H2
,以此类推,我们就利用该值最后的那个数字,乘以一个固定缩进值,这样级别递增的标题节点也就拥有了递增的缩进值,最后样式部分就可以利用 padding-left
来实现缩进,js 代码的实现思路如下:
// node 为标题节点,32 是标题级别增加而多缩进的值
node.style.paddingLeft = node.nodeName.slice(-1) * 32 + 'px';
对于点击标题跳转到文章对应标题所在位置这个功能,实现也比较简单,设置对应 锚点 即可,也就是标题元素需要设置一个 id
属性值,然后给点击的 <a>
标签的 href
属性也设置为这个 id
值即可,例如:
<h1 id="my-h1">一级标题</h1><a href="my-h1">点我跳转到一级标题</a>
具体实现
第三方库
避免重复造轮子,一些基础的格式化样式就交给第三方库去解决吧,这里使用的是 Materialize 这个库,安装和引用教程去官网:https://materializecss.com 查看;
HTML部分
具体参考代码与说明如下:
<!-- 引用第三方库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><!-- 固定于屏幕右下方的一个悬浮按钮 -->
<div class="fixed-action-btn"><a class="btn-floating btn-large blue z-depth-4"><i class="large material-icons">apps</i></a><ul><!-- 文章目录按钮 --><li class="category-btn hide"><a class="sidenav-trigger btn-floating blue lighten-2" data-target="category"><i class="material-icons">format_list_bulleted</i></a></li><!-- 下面也可以添加其他按钮,如返回文章顶部等--><li><a class="btn-floating blue lighten-2" href="javascript: scrollTo(0, 0);"><i class="material-icons">publish</i></a></li></ul>
</div><!-- 文章目录侧栏 -->
<ul id="category" class="hide sidenav grey lighten-4 grey-text text-darken-3"><li><p class="center-align">目录</p></li>
</ul><!-- 下面的元素中存放文章内容 -->
<div id="post-content"><!-- 文章内容,需要注意的只有,为不同的标题元素设置不同的 id 属性以实现跳转 --><!-- 以下为示例内容 --><h1 id="t1">Title 1</h1><p>Hello World!</p><p>Hello World!</p><h2 id="t11">Title 1</h2><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><h2 id="t12">Title 1</h2><h3 id="t121">Title 1</h3><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><h1 id="t2">Title 2</h1><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><h1 id="t3">Title 3</h1><p>Hello World!</p><h2 id="t31">Title 3</h2><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p><p>Hello World!</p>
</div>
CSS部分
样式部分因人而异,可以自行设计调整,以下为参考:
#category li a:before { /* 添加一个折叠符号,为了好看 */content: "∟";position: absolute;left: 10px;bottom: 5px;font-size: 12px;
}
JavaScript部分
该部分就是核心所在了,对应上面的 HTML 和 CSS 部分,实现如下:
// 初始化第三方库的插件
M.AutoInit();
document.addEventListener('DOMContentLoaded', function () {var elemCategory = document.querySelector('#category');M.Sidenav.init(elemCategory, {'edge': 'right' // right 表示在右侧栏显示,left 则表示在左边显示});
});var postContent = document.querySelector('#post-content');if (postContent) { // 存在文章内容var categories = postContent.querySelectorAll('h1, h2, h3, h4, h5, h6');if (categories.length > 0) { // 文章存在标题var category = document.querySelector('#category'),categoryBtn = document.querySelector('.category-btn');var li = document.createElement('li'),a = document.createElement('a');a.className = 'waves-effect';// 存在目录则显示目录按钮和侧栏category.classList.remove('hide');categoryBtn.classList.remove('hide');categories.forEach(node => {// 每次 cloneNode 取代 createElement// 因为克隆一个元素快于创建一个元素var _li = li.cloneNode(false),_a = a.cloneNode(false);_a.innerText = node.innerText;// 为标题设置跳转链接_a.href = '#' + node.id;_li.appendChild(_a);// 为不同级别标题应用不同的缩进_li.style.paddingLeft = node.nodeName.slice(-1) * 32 + 'px';category.appendChild(_li);})}
}
效果
最后附上几张本人博客网站实现的最终效果图,也欢迎点击 https://knightyun.github.io 前往访问 ^_^
技术文章推送 手机、电脑实用软件分享
个人博客网站文章添加目录导航相关推荐
- 为博客的文章添加二维码
文章地址:http://www.xiabingbao.com/blogs/2016/08/31/blogs-qrcode.html 为博客的文章添加了一个生成二维码的功能,可以在扫描二维码后在移动端进 ...
- 为博客园博文添加目录的两种方法
准备工作: 确认你的博客有js权限,可以设计界面风格.这个需要跟管理员申请. 方法一:在正文上方直接添加目录 1.把下面的脚本添加到博客后台设置里的"页脚html代码"里头: 1 ...
- 博客园文章自动生成导航目录
文章如果比较长的话,子标题很难找,文章结构没法一目了然,如果有一个导航目录靠在边栏就好了 看了很多园子里其他的文章,js和css挺长的,怕用不好,干脆自己尝试写一个 一.要实现的功能 1.自动生成 不 ...
- 博客园文章添加版权信息的方法
管理--操作--博客签名,进入到制作签名的页面.在"内容"的文本框输入如下信息并替换相应的文字: <div>作者:<a href="http://www ...
- Hexo博客yilia主题文章添加目录
参考文章 添加目录的文章有一些是自己添加css文件和修主题配置 作者也更新了文章大体目录的功能 打开配置文件themes/yilia/_config.yml 你可以选择toc设置为1 或者2 toc: ...
- 在文章右上角添加目录导航
在文章右上角添加目录导航 1.添加css代码到"页面定制css代码" 1 /*生成博客目录的CSS*/ 2 #uprightsideBar{ 3 font-size:12px; 4 ...
- github+hexo搭建自己的博客网站(六)进阶配置(搜索引擎收录,优化你的url,添加RSS)...
详细的可以查看hexo博客的演示:https://saucxs.github.io/ 绑定了域名: http://www.chengxinsong.cn hexo+github博客网站源码(可以clo ...
- 老徐的博客:文章目录
Posted on 2009-05-22 23:35 Frank Xu Lei 阅读(1850) 评论(18) 编辑 收藏 网摘 所属分类: 老徐的博客:文章目录, SOA and EAI 老徐的博 ...
- 在线文本替换工具 、支持正则表达式(博客园文章里添加Javascript或<script>语句)
概况与介绍 在博客园发布一篇文章,文章就是<在线文本替换工具 .支持正则表达式>https://www.cnblogs.com/lsllll44/articles/15522697.htm ...
最新文章
- Windows10上使用VS2017编译OpenCV3.4.2+OpenCV_Contrib3.4.2+Python3.6.2操作步骤
- posix_kill 信号
- caffe windows学习:第一个测试程序
- 统计用户在某一页停留的时间
- html用bmob做留言,bmob js-sdk 在vue中的使用教程
- 论文浅尝 | CoRR - 面向复杂知识问答的框架语义解析方法
- R语言:ggplot2精细化绘图——以实用商业化图表绘图为例(转)
- 阿里北大:深度哈希算法最新综述
- 03-25 内存统计
- 微会显示服务器当前线路忙,免费电话之争:触宝电话/微会谁更强
- linux网络安装mysql_linux系统安装mysql
- java将数据从外部读入到程序称为_java复习与练习答案beta3(基本可信~~)
- TMG自动发现功能配置正常,但客户端却检测不到TMG服务器。
- postgresql注册表删除_【清理注册表】删除SQL Server注册表
- 关于近段时间学习历史的点滴记录
- html去除图片背景颜色,canvas实现图片背景色去色变透明 » 张鑫旭-鑫空间-鑫生活...
- 4G模块 | 基于4G Cat.1的内网穿透实践
- USI环旭电子推出信用卡大小的SiPSet笔记本电脑主板
- 12个成功案例,告诉你提升客户体验新方法!
- JPA @PersistenceContext和@Transactional Annotation
热门文章
- 李洪强iOS开发之OC[012] -类的声明实现小结
- (AirWatch 系列之一)企业移动计算的集大成者--Airwatch简介
- C#中yield用法
- 通过代码解决全角问题类调用法
- 宽带路由器常见故障排除
- jsapi.php 参数设置,统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!...
- SpringMVC系列一
- 4x3矩阵键盘扫描法c语言,四种4*4矩阵键盘的扫描方法
- sublime编辑器无法正常打印中文问题解决
- Linux系统安装管理