为 Hexo 添加可折叠的文章目录

前言

Hexo 支持自动给文章加上目录,但默认生成的目录比较简陋,好在我们可以手动改进一下它,比如增加 点击展开/收起多级目录 的功能。

前期准备

目录生成

  • 比如 Yelee 主题中用以下代码自带生成目录,使用 Hexo 自带的辅助函数 <%-toc(post.content)%> 来生成文章目录,同时将目录包裹起来以便修改样式。其他主题大同小异。
1
2
3
4
<div id="toc" class="toc-article">
<strong class="toc-title">文章目录</strong>
<%- toc(post.content) %>
</div>

观察结构

  • 审查元素,观察到生成后的目录 HTML 结构大致如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div id="toc" class="toc-article">
<strong class="toc-title">文章目录</strong>
<ol class="toc">
<li class="toc-item toc-level-2">
<a class="toc-link" href="#标题1">
<span class="toc-number">1.</span> <span class="toc-text">标题1</span>
</a>
</li>
<li class="toc-item toc-level-2">
<a class="toc-link" href="#标题2">
<span class="toc-number">2.</span> <span class="toc-text">标题2</span>
</a>
<!-- 含子标题 -->
<ol class="toc-child">
<li class="toc-item toc-level-3">
<a class="toc-link" href="#子标题1"><span class="toc-number">2.1.</span> <span class="toc-text">子标题1</span>
</a>
</li>
<li class="toc-item toc-level-3">
<a class="toc-link" href="#子标题2"><span class="toc-number">2.2.</span> <span class="toc-text">子标题2</span></a>
</li>
</ol>
</li>
</ol>
</div>

功能构思

  • 在每个包含子标题的大标题前插入小图标;
  • 找出需要绑定点击事件的元素;
  • 理清每次事件中子目录折叠和小图标切换的逻辑。

代码编写

添加小图标

1
2
3
4
5
6
var $itemHasChild = $("#toc .toc-item:has(> .toc-child)");
var $titleHasChild = $itemHasChild.children(".toc-link");
$itemHasChild.prepend("<i class='fa fa-caret-down'></i><i class='fa fa-caret-right'></i>");

var $iconToFold = $(".toc-item > .fa-caret-down");
$iconToExpand.addClass("hide");

这里在匹配的大标题前插入了两个 <i> 标签,用于表示目录 展开收起 这两种状态;
标签使用了 Font Awesome 中的小三角形图标,可自行更换或者用 CSS 绘制;

点击小图标

1
2
3
4
5
6
7
8
9
10
11
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-blocknone 中切换,用 toggleClass 比较合适。

点击大标题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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");
}
})
}()
  • 这里按我自己的习惯设计成 单击 即展开目录,而折叠目录需要 双击。因为点击某个目录时,代表我希望了解该目录的内容,所以不希望单击就把对应目录给收起了;
  • 单击事件要在双击事件之后,要不点击事件会出现异常。

点击总标题

  • 之前给目录区加了个总标题 文章目录,现在可以给赋予其函数,以便点击时 展开/收起 所有目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 调整下样式即可,样式根据主题风格和个人喜好自行调整;
  • 下面是部分自用样式,可参考
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*小图标*/
#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: http://fontawesome.io/
  2. Hexo TOC 辅助函数: https://hexo.io/zh-cn/docs/helpers.html#toc
  3. 为 Hexo 博客添加目录 by 况琪 on 2015/02/09: http://kuangqi.me/tricks/enable-table-of-contents-on-hexo/
  4. feat: collapsible TOC 可折叠目录 by MOxFIVE on 2016/06/05: https://github.com/MOxFIVE/hexo-theme-yelee/commit/85764bbf482c78d819f8ca87bf9fe390d523dd3b
文章目录
  1. 1. 前言
  2. 2. 前期准备
    1. 2.1. 目录生成
    2. 2.2. 观察结构
    3. 2.3. 功能构思
  3. 3. 代码编写
    1. 3.1. 添加小图标
    2. 3.2. 点击小图标
    3. 3.3. 点击大标题
    4. 3.4. 点击总标题
    5. 3.5. CSS 样式
  4. 4. 相关链接
|