Hexo-Fluid 功能拓展--目录全展开

Hexo-Fluid 功能拓展—目录全展开

在Fluid主题仓库看到有人提出相应的issue,是个容易实现的功能,相对也比较实用。希望实现类似效果的读者直接复制下文代码到对应文件即可。

1. 修改主题配置文件

_config.fluid.yml文件中添加以下配置:

1
2
3
4
5
6
7
8
9

# 侧边栏展示文章目录
# Table of contents (TOC) in the sidebar
toc:
enable: true
# 进入文章时是否默认展开全部目录
# Expand all TOC items on enter
expand_all: true

如果你还没有执行Hexo Fluid 覆盖配置的操作,你需要修改的文件应该是themes\fluid\_config.yml

2. 修改主题文件

themes\fluid\source\css\_pages\_base\_widget\toc.styl文件中添加/修改如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.toc-toggle
display inline-block
width 1rem
text-align center
margin-right .25rem
cursor pointer
user-select none
color var(--text-color)
font-size .75rem
line-height 1
transition transform .2s ease-in-out

&.toc-toggle-collapsed
transform rotate(0deg)

&.toc-toggle-expanded
transform rotate(90deg)

# 仅占位用于对齐缩进,不参与交互
&.toc-toggle-placeholder
visibility hidden
pointer-events none
cursor default
transform none

完整代码如下:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#toc
visibility hidden

.toc-header
margin-bottom .5rem
font-weight bold
line-height 1.2

&, & > i
font-size 1.25rem

.toc-body
max-height 75vh
overflow-y auto
overflow -moz-scrollbars-none
-ms-overflow-style none

ol
list-style none
padding-inline-start 1rem

&::-webkit-scrollbar
display none

.tocbot-list
position relative

ol
list-style none
padding-left 1rem

a
font-size 0.95rem

.tocbot-link
color var(--text-color)

.toc-toggle
display inline-block
width 1rem
text-align center
margin-right .25rem
cursor pointer
user-select none
color var(--text-color)
font-size .75rem
line-height 1
transition transform .2s ease-in-out

&.toc-toggle-collapsed
transform rotate(0deg)

&.toc-toggle-expanded
transform rotate(90deg)

# 仅占位用于对齐缩进,不参与交互
&.toc-toggle-placeholder
visibility hidden
pointer-events none
cursor default
transform none

.tocbot-active-link
font-weight bold
color var(--link-hover-color)

.tocbot-is-collapsed
max-height 0

.tocbot-is-collapsible
overflow hidden
transition all .3s ease-in-out

.toc-list-item
white-space nowrap
overflow hidden
text-overflow ellipsis

&.is-active-li::before
height 1rem
margin 0.25rem 0
visibility visible

&::before
width 0.15rem
height 0.2rem
position absolute
left 0.25rem
content ""
border-radius 2px
margin 0.65rem 0
background var(--link-hover-color)
visibility hidden
transition height .1s ease-in-out, margin .1s ease-in-out, visibility .1s ease-in-out

.sidebar
position -webkit-sticky
position sticky
top 2rem
padding 3rem 0

针对themes\fluid\layout\_partials\post\toc.ejs也需要做对应修改,下直接给出完整代码:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<div id="toc">
<p class="toc-header">
<i class="iconfont icon-list"></i>
<span><%- __('post.toc') %></span>
</p>
<div class="toc-body" id="toc-body"></div>
</div>

<%
import_script(`
<script>
Fluid.utils.createScript('${url_join(theme.static_prefix.tocbot, 'tocbot.min.js')}', function() {
var toc = jQuery('#toc');
if (toc.length === 0 || !window.tocbot) { return; }
var boardCtn = jQuery('#board-ctn');
var boardTop = boardCtn.offset().top;

function isExpandAllEnabled() {
return CONFIG.toc && CONFIG.toc.expand_all === true;
}
function expandAllToc() {
if (!isExpandAllEnabled()) { return; }
jQuery('#toc-body .tocbot-is-collapsed').removeClass('tocbot-is-collapsed');
}
function updateTocToggle($li, $childList) {
var $toggle = $li.children('.toc-toggle');
if ($toggle.length === 0) { return; }
var collapsed = $childList.hasClass('tocbot-is-collapsed');
// 统一使用 ▶ 字符,通过旋转控制方向
$toggle
.toggleClass('toc-toggle-collapsed', collapsed)
.toggleClass('toc-toggle-expanded', !collapsed);
}
function bindTocToggle() {
if (!isExpandAllEnabled()) { return; }
jQuery('#toc-body .toc-list-item').each(function() {
var $li = jQuery(this);
var $childList = $li.children('ol');
// 没有子目录的条目也需要占位,保证缩进对齐
if ($childList.length === 0) {
if ($li.children('.toc-toggle').length === 0) {
$li.prepend('<span class="toc-toggle toc-toggle-placeholder" aria-hidden="true">▶</span>');
}
return;
}

if ($li.children('.toc-toggle').length === 0) {
// 统一使用 ▶ 字符,后续通过 CSS 旋转控制展开/折叠方向
$li.prepend('<span class="toc-toggle toc-toggle-expanded" aria-hidden="true">▶</span>');
}
updateTocToggle($li, $childList);
});
jQuery('#toc-body').off('click.tocToggle').on('click.tocToggle', '.toc-toggle', function(e) {
e.preventDefault();
e.stopPropagation();
var $li = jQuery(this).parent('.toc-list-item');
var $childList = $li.children('ol');
if ($childList.length === 0) { return; }
$childList.toggleClass('tocbot-is-collapsed');
updateTocToggle($li, $childList);
});
if (!window.__tocToggleObserver) {
window.__tocToggleObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type !== 'attributes' || mutation.attributeName !== 'class') { return; }
var $list = jQuery(mutation.target);
var $li = $list.parent('.toc-list-item');
if ($li.length === 0) { return; }
updateTocToggle($li, $list);
});
});
jQuery('#toc-body ol').each(function() {
window.__tocToggleObserver.observe(this, { attributes: true });
});
}
}
var tocConfig = Object.assign({
tocSelector : '#toc-body',
contentSelector : '.markdown-body',
linkClass : 'tocbot-link',
activeLinkClass : 'tocbot-active-link',
listClass : 'tocbot-list',
isCollapsedClass: 'tocbot-is-collapsed',
collapsibleClass: 'tocbot-is-collapsible',
scrollSmooth : true,
includeTitleTags: true,
headingsOffset : -boardTop,
}, CONFIG.toc);
if (isExpandAllEnabled()) {
tocConfig.collapseDepth = 6;
}
window.tocbot.init(tocConfig);
if (toc.find('.toc-list-item').length > 0) {
toc.css('visibility', 'visible');
}
expandAllToc();
bindTocToggle();

Fluid.events.registerRefreshCallback(function() {
if ('tocbot' in window) {
tocbot.refresh();
var toc = jQuery('#toc');
if (toc.length === 0 || !tocbot) {
return;
}
if (toc.find('.toc-list-item').length > 0) {
toc.css('visibility', 'visible');
}
expandAllToc();
bindTocToggle();
}
});
});
</script>
`)
%>

Hexo-Fluid 功能拓展--目录全展开
http://ruak.github.io/2026/01/23/Hexo-Fluid-功能拓展-目录全展开/
作者
HUANGDAN
发布于
2026年1月23日
许可协议