闲了好一阵子,最近突来兴趣,再扒洪哥的博客。

关于页面动态分类条,洪哥早已提供教程(HEO:Butterfly魔改动态分类条)。本文主要分享,在此基础上增强支持自定义页面的心得(原版只支持“分类”)。

注意看,小游戏这个内容(path为/game/)并非分类或子分类,而是我自定义的一个页面,包含了一些自部署的趣味游戏。原本洪哥的方法,在小游戏页面是无法展示上述“分类条”的,点击进入这个页面后,分类条上的小游戏也无法自动高亮。所以,以下为个人再次魔改内容。

效果预览

动态分类条

实现方式

新建categoryBar.pug

洪哥版本上,调整为配置化,方便随时修改。不然老去改源码有点不优雅。新建以下文件:themes/butterfly/layout/includes/categoryBar.pug ,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
if theme.DynamicCategoryBar.enable && theme.DynamicCategoryBar.category !== undefined 
#category-bar
.category-bar-items#category-bar-items
each item in theme.DynamicCategoryBar.category
if (item.name == undefined || item.id == undefined || item.url == undefined)
- console.log('DynamicCategoryBar:当前存在某项配置异常,已跳过其渲染(配置指引:https://blog.guole.fun/posts/13386/)')
else
.category-bar-item(id=item.id)
a(href=item.url)= _p(item.name)
#category-bar-next.category-bar-next(onclick="scrollCategoryBarToRight()")
//- i.fa-solid
a.category-bar-more(href="/categories/")= _p('更多')

引用模板

themes/butterfly/layout/index.pug文件中,+postUI上新增一行内容include includes/categoryBar.pug,注意缩进。

注意缩进呀~

1
2
+   include includes/categoryBar.pug
+postUI
1
2
3
4
5
6
7
8
extends includes/layout.pug

block content
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts
include includes/categoryBar.pug
+postUI
include includes/pagination.pug

themes/butterfly/layout/category.pug文件中,#category下新增以下内容:

1
2
3
4
.category-in-bar
.category-in-bar-tips
| 分类
include includes/categoryBar.pug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
extends includes/layout.pug

block content
if theme.category_ui == 'index'
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts.category_ui
+postUI
include includes/pagination.pug
else
include ./includes/mixins/article-sort.pug
#category
.category-in-bar
.category-in-bar-tips
| 分类
include includes/categoryBar.pug
.article-sort-title= _p('page.category') + ' - ' + page.category
+articleSort(page.posts)
include includes/pagination.pug

继续引用

编辑themes/butterfly/layout/page.pug文件,主要是实现了关联任意自定义页面

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
extends includes/layout.pug

block content
#page
+ if (page.type == 'categoryBar')
+ #category
+ .category-in-bar
+ .category-in-bar-tips
+ | 分类
+ include includes/categoryBar.pug
if top_img === false
h1.page-title= page.title

case page.type
when 'tags'
include includes/page/tags.pug
when 'link'
include includes/page/flink.pug
when 'categories'
include includes/page/categories.pug
when 'about'
include includes/page/about.pug
+ when 'categoryBar'
+ include includes/page/default-page.pug
default
include includes/page/default-page.pug

if page.comments !== false && theme.comments && theme.comments.use
- var commentsJsLoad = true
!=partial('includes/third-party/comments/index', {}, {cache: true})
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
extends includes/layout.pug

block content
#page
if (page.type == 'categoryBar')
#category
.category-in-bar
.category-in-bar-tips
| 分类
include includes/categoryBar.pug
if top_img === false
h1.page-title= page.title

case page.type
when 'tags'
include includes/page/tags.pug
when 'link'
include includes/page/flink.pug
when 'categories'
include includes/page/categories.pug
when 'about'
include includes/page/about.pug
when 'categoryBar'
include includes/page/default-page.pug
default
include includes/page/default-page.pug

if page.comments !== false && theme.comments && theme.comments.use
- var commentsJsLoad = true
!=partial('includes/third-party/comments/index', {}, {cache: true})

配置自定义页面

若某个页面想添加进分类条(非分类页),则需要在其.md文件头,设置type: categoryBar。这样就能自动把分类条插入进去渲染了。

比如,我的/game/index.md,文件头就是下面这样:

1
2
3
4
title: 休闲小游戏
date: 2023-01-09 11:01:05
top_img: false
type: "categoryBar"

新建js

如果你还没有独立的自定义js文件,可以考虑新建一个,建议放到root/source/js/(root为你的blog项目根目录)。随后,在_config.butterfly.ymlinject:bottom:中新增一条内容,假如这个文件叫diy.js

1
- <script async defer src='/js/diy.js'></script>

diy.js内容为:

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
//动态分类条
var pathInfo = window.location.pathname;
function categoriesBarActive() {
pathInfo = decodeURIComponent(pathInfo)
// console.log(pathInfo);
//判断是否是首页
if (pathInfo == '/') {
if (document.querySelector('#category-bar')) {
document.getElementById('首页').classList.add("select")
}
} else {
// 验证是否是分类链接
const pattern = /\/categories\/.*?\//;
let patbool = pattern.test(pathInfo);
let valuegroup = pathInfo.split("/");
for (let n = 0; n <= valuegroup.length; n++) {
n = valuegroup.length;
var nowCategorie = valuegroup[n - 2];
}
// console.log(patbool);
if (patbool) {
// console.log(valuegroup[2]);
if (document.getElementById(nowCategorie)) {
document.getElementById(nowCategorie).classList.add("select");
}
} else {
let id;
switch (nowCategorie) {
case 'game':
id = '小游戏';
break;
}
if (document.querySelector('#category-bar')) {
document.getElementById(id).classList.add("select");
}
}
}
categoriesBarNext()
}
//翻页按钮
function scrollCategoryBarToRight() {
var e = document.getElementById("category-bar-items")
, t = document.getElementById("category-bar-next")
, o = e.clientWidth;
e && (e.scrollLeft + e.clientWidth >= e.scrollWidth ? (e.scroll({
left: 0,
behavior: "smooth"
}),
t.innerHTML = '<i class="fa-solid fa-chevrons-right"></i>') : e.scrollBy({
left: o,
behavior: "smooth"
}))
}
//新增方法:动态插入翻页按钮
function categoriesBarNext() {
if (document.getElementById("category-bar-items")) {
let e = document.getElementById("category-bar-items")
, t = document.getElementById("category-bar-next")
if (e.scrollWidth > e.clientWidth) {
t.innerHTML = '<i class="fa-solid fa-chevrons-right"></i>'
} else if (t.children[0]) {
const iElement = document.querySelector('.category-bar-next i');
const parentElement = document.getElementById('category-bar-next');

parentElement.removeChild(iElement);
}
}
}
//窗口改变就执行
window.onresize = function() {
categoriesBarNext()
}

//鼠标控制横向滚动
function topCategoriesBarScroll() {
if (document.getElementById("category-bar-items")) {
let xscroll = document.getElementById("category-bar-items");
xscroll.addEventListener("mousewheel", function (e) {
//计算鼠标滚轮滚动的距离
let v = -e.wheelDelta / 2;
xscroll.scrollLeft += v;
//阻止浏览器默认方法
e.preventDefault();
}, false);
}
}
//方法调用
categoriesBarActive()
topCategoriesBarScroll()
document.addEventListener("pjax:complete", (function () {
categoriesBarActive()
topCategoriesBarScroll()
}))

配置分类条内容

在主题配置文件_config.butterfly.yml适当位置,新增以下内容:

参数说明

字段是否必填释义取值来源
enableY分类条开关
nameY分类条上展示的分类项名称自定义
idY唯一值,根据这个实现点击切换自定义,支持中文
urlY页面path,即待添加页面的访问 URL ,去除域名剩余的部分path
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
# 动态分类条
# 使用指南:https://guole.fun/posts/13386/
# --------------------------------------
DynamicCategoryBar:
enable: true
category:
- name: 首页
id: 首页
url: '/'
- name: 经验分享
id: 经验分享
url: '/categories/经验分享/'
- name: NPM插件
id: NPM插件
url: '/categories/NPM插件/'
- name: 小游戏
id: 小游戏
url: '/game/'
- name: 找点儿乐子
id: 找点儿乐子
url: '/categories/找点儿乐子/'
- name: 文案摘录
id: 文案摘录
url: '/categories/文案摘录/'
- name: 给生活加点颜色
id: 给生活加点颜色
url: '/categories/给生活加点颜色/'
- name: 胡思乱想
id: 胡思乱想
url: '/categories/胡思乱想/'

引入css

同上,可以直接放到你自己的自定义样式表里,如果没有就新建一个。在_config.butterfly.ymlinject:head:中新增一条内容,假如这个文件叫diy.css

1
2
- <link rel="stylesheet" href="/css/diy.css" media="print" onload="this.media='all'">
- <link rel="stylesheet" href="/css/color.css" media="print" onload="this.media='all'">

前前后后改了好几次,如有样式问题,可在本站自行查找调整。

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
/* 首页分类条展示 */
#category-bar {
padding: 0.4rem 1rem 0.4rem 0.7rem;
display: flex;
white-space: nowrap;
overflow: hidden;
transition: 0.3s;
justify-content: space-between;
-webkit-user-select: none;
user-select: none;
align-items: center;
}

#category-bar,
.category-in-bar-tips {
margin-bottom: 0.75rem;
box-shadow: 0 8px 16px -4px #2c2d300c;
animation: slide-in 0.6s 0.3s backwards;
}

#category #category-bar {
padding: 0;
border: none;
}

#category a.category-bar-item.select a {
display: none;
}

.category-in-bar {
display: flex;
white-space: nowrap;
align-items: center;
}

.category-in-bar-tips {
margin-right: 1rem;
margin-top: 0.25rem;
}

@media screen and (max-width: 768px) {
.category-in-bar-tips {
margin-right: 0.2rem;
}
}

.category-bar-items {
white-space: nowrap;
overflow-x: scroll;
overflow-y: hidden;
display: flex;
border-radius: 8px;
align-items: center;
height: 30px;
}

.category-bar-items::-webkit-scrollbar {
display: none;
}

.category-bar-item a {
color: var(--font-color);
padding: 0.1rem 0.5rem;
margin-right: 6px;
font-weight: bold;
border-radius: 8px;
display: flex;
align-items: center;
height: 30px;
}

.category-bar-item:hover a {
background: var(--guole-color-hover);
color: #fff;
}

.category-bar-item.select a {
background: var(--guole-color-hover);
color: #fff;
border-radius: 12px;
}

.category-bar-more {
margin-left: 1rem;
font-weight: bold;
color: var(--font-color);
}

.category-bar-next {
margin-left: 16px;
cursor: pointer;
display: flex;
}

.category-bar-next:hover {
color: var(--guole-main);
}

.category-bar-next i::before{
content: "\f101";
}

#page > #category > .category-in-bar {
border-bottom: 2px solid var(--guole-card-border);
}

为什么要再新建一个color.css?因为实测,diy.css内容与color.css放一起,定义的颜色不生效……分开也方便管理。色值可以按你自己的主题色调整。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
:root {
--guole-theme-color: #1c69ed;
--guole-main: var(--guole-theme-color);
}

[data-theme=light] {
--guole-color-hover: #1c69ed;
--guole-card-border: rgba(66, 68, 74, .15);
}

[data-theme=dark] {
--guole-color-hover: #11459d;
--guole-card-border: rgba(66, 68, 74, .5);
}

后续新增分类

若新增项为分类页面(path为/categories/……/类型),直接编辑_config.butterfly.yml即可。

1
2
3
4
5
6
DynamicCategoryBar:
enable: true
category:
+ - name: NPM插件
+ id: NPM插件
+ url: '/categories/NPM插件/'
  1. 还是先配置_config.butterfly.yml,新增内容
    1
    2
    3
    4
    5
    6
    DynamicCategoryBar:
    enable: true
    category:
    + - name: 关于本站
    + id: 关于本站
    + url: '/about/'
  2. 编辑diy.js
    在原有switch中,新增一个case

    小贴士:

    • ‘about’: 即category.pug中,你填写的a标签href属性值,也就是这个自定义页面实际访问时的path
    • id: 即category.pug中,你设置的id
    1
    2
    3
    4
    5
    6
    7
    8
          switch (nowCategorie) {
    case 'game':
    id = '小游戏';
    break;
    + case 'about':
    + id = '关于本站';
    + break;
    }

在对应独立页面的.md文件头,设置type: categoryBar

大功告成,hexo三连,看看效果吧。