title: 为 Hexo 添加可折叠的文章目录
date: 2016-06-13 20:06:30
categories: 术业专攻
tags:
- Hexo
- jQuery
fancybox: false
permalink: hexo-collapsible-toc
---
前言
Hexo 支持自动给文章加上目录,但默认生成的目录比较简陋,好在我们可以手动改进一下它,比如增加 点击展开/收起多级目录 的功能。
## 前期准备
### 目录生成
- 比如 [Yelee](https://github.com/MOxFIVE/hexo-theme-yelee/) 主题中用以下代码自带生成目录,使用 Hexo 自带的辅助函数 `<%-toc(post.content)%>` 来生成文章目录,同时将目录包裹起来以便修改样式。其他主题大同小异。
```erb
文章目录
<%- toc(post.content) %>
```
### 观察结构
- 审查元素,观察到生成后的目录 HTML 结构大致如下
```html
```
### 功能构思
- 在每个包含子标题的大标题前插入小图标;
- 找出需要绑定点击事件的元素;
- 理清每次事件中子目录折叠和小图标切换的逻辑。
## 代码编写
### 添加小图标
```js
var $itemHasChild = $("#toc .toc-item:has(> .toc-child)");
var $titleHasChild = $itemHasChild.children(".toc-link");
$itemHasChild.prepend("");
var $iconToFold = $(".toc-item > .fa-caret-down");
$iconToExpand.addClass("hide");
```
> 这里在匹配的大标题前插入了两个 `` 标签,用于表示目录 `展开` 和 `收起` 这两种状态;
> 标签使用了 [Font Awesome](http://fontawesome.io/) 中的小三角形图标,可自行更换或者用 CSS 绘制;
### 点击小图标
```js
var clickIcon = function(){
$("#toc .toc-item > i").click(function(){
$(this).siblings(".toc-child").slideToggle(100);
$(this).toggleClass("hide");
$(this).siblings("i").toggleClass("hide");
})
}()
// 默认展开目录,所以隐藏掉表示“目录已展开”的图标(向下的小三角)
var $iconToFold = $(".toc-item > .fa-caret-down");
$iconToExpand.addClass("hide");
```
> - 点击小图标折叠次级目录,同时切换到相应图标;
> - 这里图标的显示状态是在 `inline-block` 和 `none` 中切换,用 `toggleClass` 比较合适。
### 点击大标题
```js
var clickTitle = function(){
$titleHasChild.dblclick(function(){
$(this).siblings(".toc-child").hide(100);
$(this).siblings("i").toggleClass("hide");
})
// After dblclick enent
$titleHasChild.click(function(){
var $curentTocChild = $(this).siblings(".toc-child");
if ($curentTocChild.is(":hidden")) {
$curentTocChild.show(100);
$(this).siblings("i").toggleClass("hide");
}
})
}()
```
> - 这里按我自己的习惯设计成 `单击` 即展开目录,而折叠目录需要 `双击`。因为点击某个目录时,代表我希望了解该目录的内容,所以不希望单击就把对应目录给收起了;
> - 单击事件要在双击事件之后,要不点击事件会出现异常。
### 点击总标题
- 之前给目录区加了个总标题 `文章目录`,现在可以给赋予其函数,以便点击时 展开/收起 所有目录
```js
var clickTocTitle = function(){
var $iconToExpand = $(".toc-item > .fa-caret-right");
var $iconToFold = $(".toc-item > .fa-caret-down");
var $subToc = $titleHasChild.next(".toc-child");
var $tocTitle = $("#toc .toc-title");
// 当包含多级目录时再执行
if ($titleHasChild.length) {
$tocTitle.addClass("clickable");
$tocTitle.click(function(){
if ($subToc.is(":hidden")) {
$subToc.show(150);
$iconToExpand.removeClass("hide");
$iconToFold.addClass("hide");
} else {
$subToc.hide(100);
$iconToExpand.addClass("hide");
$iconToFold.removeClass("hide");
}
})
}
}()
```
### CSS 样式
- 功能函数设置好后,再通过 CSS 调整下样式即可,样式根据主题风格和个人喜好自行调整;
- 下面是部分自用样式,可参考
```css
/*小图标*/
#toc ol.toc li.toc-item i {
display: inline-block;
margin-left: -0.9em;
width: 0.9em;
color: #b3b3b3;
font-weight: bold;
cursor: pointer;
}
#toc ol.toc li.toc-item i:hover {
color: #000;
}
/*关联图标的 Class*/
#toc ol.toc li.toc-item i.hide {
display: none;
}
/*关联总标题的 Class*/
#toc .toc-title.clickable {
cursor: pointer;
}
#toc .toc-title.clickable:hover {
color: #88acdb;
}
#toc .toc-title.clickable:active {
color: #d3d3d3;
}
/*其他目录相关*/
#toc {
font-size: 0.9em;
line-height: 1.65em;
}
#toc .toc-title {
font-weight: bold;
color: #808080;
}
#toc ol.toc {
margin-left: 0;
padding: 0.7em;
padding-right: 0;
}
#toc ol.toc li.toc-item {
list-style-type: none;
}
#toc ol.toc li.toc-item:hover {
background: none;
}
#toc ol.toc a.toc-link {
color: #808080;
}
#toc ol.toc a.toc-link:visited {
color: #f48385;
}
#toc ol.toc a.toc-link:hover {
color: #88acdb;
text-decoration: none;
background: rgba(158,188,226,0.21);
}
#toc ol.toc ol.toc-child {
padding-left: 1.25em;
margin: 4px 0;
}
```
## 相关链接
1. **Font Awesome**:
1. **Hexo TOC 辅助函数:** https://hexo.io/zh-cn/docs/helpers.html#toc
1. ***为 Hexo 博客添加目录*** by **况琪** on 2015/02/09
:
1. ***feat: collapsible TOC 可折叠目录*** by **MOxFIVE** on 2016/06/05
: