更新于 

主题魔改

Hexo x Butterfly主题配置与魔改

简言

Butterfly是一款公认最好的Hexo卡片风格主题,可玩性强,使用人数多。可以说,Butterfly就像蝴蝶一样遍布了互联网。本文会通过范例 - 效果 - 配置的方式帮助您配置与魔改您的Butterfly。
Butterfly官方图

大佬们的博客

HEO:https://blog.zhheo.com

Akilar:https://akilar.top

当然冰老师的博客也非常的棒。

HEO的博客魔改程度过于大,结构更改过于繁杂,非常难改,目前我们只能提供稳定的老版本Nav,老版本的home-top与不稳定的top-img提取主色调+特效。

新版的带有TodayCard的home-top正在魔改中,新版的nav因css适配过于繁杂已被编写组取消。

(人话:能力不行,TodayCard已经实现了但有BUG,Nav Bug多到不行,看着这么多css有点晕,所以不改了。)

创建页面

在Hexo根目录打开命令行,输入:

1
hexo new page [页面名称(随便取,最好英文)]

自带功能页面

模板往往会开发一些自带功能的页面,我们称为”自带功能页面“,它往往无需多余配置,您可以在创建的页面内使用它。
Butterfly主题自带的页面有tags,categories,link。
您只需在Hexo根目录完成”创建页面”内的操作,打开 source/[您输入的页面名称]/index.md 在FrontMatter内添加type: "自带页面名称"即可。

友情链接设置

在Hexo博客目录中的source/_data(如果没有 _data 文件夹,请自行创建),创建一个文件link.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- class_name: 友情链接
class_desc: 那些人,那些事
link_list:
- name: Hexo
link: https://hexo.io/zh-tw/
avatar: https://d33wubrfki0l68.cloudfront.net/6657ba50e702d84afb32fe846bed54fba1a77add/827ae/logo.svg
descr: 快速、简单且强大的网志框架

- class_name: 网站
class_desc: 值得推荐的网站
link_list:
- name: Youtube
link: https://www.youtube.com/
avatar: https://i.loli.net/2020/05/14/9ZkGg8v3azHJfM1.png
descr: 视频网站
- name: Weibo
link: https://www.weibo.com/
avatar: https://i.loli.net/2020/05/14/TLJBum386vcnI1P.png
descr: 中国最大社交分享平台
- name: Twitter
link: https://twitter.com/
avatar: https://i.loli.net/2020/05/14/5VyHPQqR6LWF39a.png
descr: 社交分享平台

class_name 和 class_desc 支持 html 格式书写,如不需要,也可以留空。

自定义页面

自定义页面的配置方式一样简单,通常您只需要依照您正在查看教程更改便可。如果您想自己开发,您可以使用markdown与html。

简单的自定义页面配置

此章应该是涉及到魔改知识的第一张了,拿图库举例,您只需创建页面在页面的index.md中插入以下内容即可

1
2
3
<div class="gallery-group-main">
{% galleryGroup '图库卡片名称' '卡片介绍' '图片页面地址(可以是第三方链接,亦可以是本地,如:https://butterfly.js.org/Gallery/wallpaper,更多查看"子页面"' 图库卡片封面 %}
</div>

div内的内容您可以肆无忌惮的使用在所有地方,因为那是模板自带的外挂标签。(个人认为不应命名为标签,应命名为容器。)
效果如下:
外挂标签
更多外挂标签请看 # 外挂标签

子页面

子页面也是普通的页面,你只需要hexo n page xxxxx 创建你的页面就行。
在简单的自定义页面配置内,图库的外挂标签写法中”(图片页面地址 (可以是第三方链接,亦可是本地)”中的图片页面地址,一般就是子页面,一般子页面都使用图库的外挂标签。
创建页面后插入以下内容:

1
2
3
4
5
6
7
8
9
10
{% gallery %}
![](图片链接)
![](图片链接)
![](图片链接)
![](图片链接)
![](图片链接)
![](图片链接)
![](图片链接)
![](图片链接)
{% endgallery %}

效果如下:
图片页

主题配置

https://butterfly.js.org/posts/4aa8abbe/ 请勿配置pwa,pjax。

魔改技巧

魔改主要看个人喜好,如HEO的Arcylic。
学会抄写css也是非常重要的,如HEO的主页,如果您采用了他的css,您会发现许多问题。有些大佬会改变主题原有的结构或文件,请移步至Akilar与HEO的博客。

提取主色调

引入自定义javascript,引入https://blog.jayhrn.com/js/rgbaster.min.js ,在自定义javascript内添加以下配置:

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
if (document.getElementById('post-cover-img')) {
let list = []
for (let i = 0; i <= 5; i++) {
for (let j = 0; j <= 5; j++) {
for (let k = 0; k <= 5; k++) {
list.push(`rgb(${i},${j},${k})`)
list.push(`rgb(${255 - i},${255 - j},${255 - k})`)
}
}
}
RGBaster.colors(document.getElementById('post-cover-img').getAttribute('src'), {
paletteSize: 30,
exclude: list,
success: function (payload) {
const c = payload.dominant.match(/\d+/g)
const grayLevel = c[0] * 0.299 + c[1] * 0.587 + c[2] * 0.114
document.styleSheets[0].addRule(':root', `
--main: ${payload.dominant};
--second: ${grayLevel >= 192 ? '#000' : '#FFF'};
--main-light: rgba(${c[0]}, ${c[1]}, ${c[2]}, .4);
--main-shadow: 0 2px 3px 1px rgba(${c[0]}, ${c[1]}, ${c[2]}, .2);
--cover-text: ${grayLevel >= 192 ? '#4C4948' : '#EEE'};
--cover-bg: rgba(${c[0]}, ${c[1]}, ${c[2]});
`)
}
})
} else {
document.styleSheets[0].addRule(':root', `
--main: #425AEF;
--second: #FFF;
--main-light: rgba(73, 177, 245, .4);
--main-shadow: 0 2px 3px 1px rgba(73, 177, 245, .2);
--cover-text: #EEE;
--cover-bg: #49B1F5;
`
}

document.styleSheets[0].addRule('[data-theme="dark"]', `
--main: #425AEF !important;
--second: #EEE !important;
--main-light: rgba(92, 92, 92, .4) !important;
--main-shadow: 0 2px 3px 1px rgba(92, 92, 92, .2) !important;
`)

那么,尽情变量吧。当然可能会出现某些BUG,可能有关于异步与PJAX。
当然,Eurkon大佬的全部的文章头图效果除了Javascript外仅仅更改css,pug并无更改。(应为只改css所以···懒得···写了)

Home-Top

::: tip 关于我们的修改方式
对于我们来说更倾向于简单粗暴的方式(Bug相对来说比较多),即:复制HTML > HTML转CSS > 新建PUG > 粘贴内容 > 修改对应CSS > 修改对应JavaScript。
(教程编写日期:22/11/16)如TodayCard的配套JS为:

1
2
3
4
5
hideTodayCard: function() {
if (document.getElementById("todayCard")) {
document.getElementById("todayCard").classList.add('hide');
}
},

:::

在/layout/includes/layout.pug增加:

1
2
3
4
5
6
7
8
9
if page.type !== '404'
#body-wrap(class=pageType)
include ./header/index.pug
include ./hometop.pug
main#content-inner.layout(class=hideAside)
if body
div!= body
else
block content
1. 创建首页顶部模块

1.1 创建hometop.pug
在themes/butterfly/layout/includes路径下创建hometop.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
31
32
33
if is_home()
#home_top
include bbTimeList.pug
.home_top_group
#homeTopGroup.homeTopGroup
#banner_group
#banners
include sticky.pug //轮播图
.category_group
.category_item
a.category_button(href=<左下角标签1路径>,style="background:linear-gradient(to right,#364f6b,#3fc1c9)")
span.category_button_text <标签1名称>
i.fas.fa-laptop-code
.category_item
a.category_button(href=<左下角标签2路径>,style="background:linear-gradient(to right,#6639a6,#3490de)")
span.category_button_text <标签2名称>
i.fas.fa-lightbulb
.category_item
a.category_button(href=<左下角标签3路径>,style="background:linear-gradient(to right,#f65,#ffbf37)")
span.category_button_text <标签3名称>
i.fas.fa-book
.top_post_group // 右侧文章推荐卡片
if site.data.slider
each i in site.data.slider
.top_post_item
.post_cover
a(href=url_for(i.link) title=i.title)
img.post_bg.entered.loaded(src=url_for(i.cover))
.post_cover_info
p.post_cover_text= i.description

.post_info(onclick=`"window.open(`+url_for(i.link)+`,"_self")"`)
a.article-title(href=url_for(i.link) title=i.title)= i.title

其中第一行的is_home()是Hexo自带的辅助函数,用于判断是否为首页,但是其在justlovesmile.top/以及justlovesmile.top/page/2/等页面都返回True,因此如果你只想在首页的第一页显示该模块,可以使用is_current(‘/‘)。

1.2 添加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
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
:root{
--mj-white: #fff;
--mj-card-bg: #fff;
--mj-theme: #425AEF;
--mj-main: #425AEF;
--mj-secondbg: #ededed;
--mj-card-border: #e3e8f7;
--style-border: 1px solid var(--mj-card-border);
--style-hover-border: 1px solid var(--mj-theme);
}
/* home top */
#home_top {
max-width: 1500px;
width: 100%;
margin-top: .5rem;
padding: 0 15px;
margin: 0 auto;
}
.home_top_group {
border-radius: 12px;
overflow: auto;
width: 100%;
margin-bottom: 0;
}
.homeTopGroup {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
margin-top: 1rem;
overflow: auto;
overflow-x: score;
border-radius: 12px;
}
.homeTopGroup::-webkit-scrollbar {
display: none;
}
.homeTopGroup #banner_group {display: flex;}
div#banners {display: none;}
@media screen and (min-width: 1300px){
.homeTopGroup #banner_group {
width: calc(100% - 600px - 1.5rem);
display: flex;
flex-direction: column;
justify-content: space-between;
}
div#banners {
display: flex;
width: 100%;
height: 100%;
background: var(--mj-main);
margin-bottom: .5rem;
margin-right: .5rem;
border: var(--style-border);
border-radius: 12px;
overflow: hidden;
position: relative;
}
div#banners:hover{
border: var(--style-hover-border);
}
.homeTopGroup .category_group {
flex-direction: row !important;
}
.homeTopGroup .category_item {
width: calc(100% / 3 - .33rem);
height: 100% !important;
margin-right: .5rem;
}
.homeTopGroup .category_item:nth-child(3) {
margin-right: 0;
display: flex !important;
}
#banner-page {
width: 100%;
height: 100%;
}
.top_post_group {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-end;
height: calc(328px + .5rem);
align-content: space-between;
width: calc(600px + 1.5rem);
}
}

.homeTopGroup .category_group{
display: flex;
flex-direction: column;
justify-content: space-between;
min-width: 200px;
}
.homeTopGroup .category_item {
overflow: hidden;
transform: scale(1);
transition: .3s;
height: 48%;
border-radius: 12px;
}
.homeTopGroup .category_item:nth-child(3) {
display: none;
}
.homeTopGroup .category_item a.category_button {
height: 100%;
width: 100%;
background: var(--mj-card-bg);
border-radius: 12px;
display: inline-block;
text-align: left;
line-height: 4em;
font-weight: 700;
font-size: .9rem;
color: var(--mj-white);
transition: all .4s cubic-bezier(.39,.575,.565,1);
transform: scale(1);
overflow: hidden;
font-family: PingFang SC,Hiragino Sans GB,Microsoft YaHei;
}
.category_button_text {
padding-left: 25px;
}
a.category_button i {
font-size: 3rem;
opacity: .3;
position: absolute;
right: 15px;
top: 10%;
transition: .3s;
transform: rotate(-10deg);
/*width: 100px;
text-align: center;*/
}
a.category_button:hover i {
opacity: .8;
transition: .8s;
transition-delay: .15s;
transform: scale(1.1)
}
a.category_button:hover:after{
width: 3rem;
transition: .8s;
}
a.category_button:after {
top: 40px;
width: 1rem;
left: 25px;
height: 2px;
background: var(--mj-white);
content: "";
border-radius: 1px;
position: absolute;
transition: .8s;
}
@media screen and (max-width: 768px){
#home_top{
padding: 0 5px;
}
.homeTopGroup .category_group {
min-width: 130px!important;
}
.top_post_group .top_post_item{
border-radius: 0;
}
}
.top_post_group{
display: flex;
position: relative;
}
.top_post_group .top_post_item {
display: flex;
width: 200px;
min-width: 200px;
height: 164px;
max-height: 164px;
flex-direction: column;
align-items: flex-start;
margin-left: .5rem;
background: var(--mj-card-bg);
border-radius: 12px;
overflow: hidden;
border: var(--style-border);
}
.top_post_group .top_post_item:hover {border: var(--style-hover-border);}
.top_post_group .top_post_item .post_cover {
width: 100%;
height: 110px;
position: relative;
}
.top_post_group .top_post_item .post_cover img {
object-fit: cover;
width: 100%;
height: 110px;
background: var(--mj-secondbg);
}
.top_post_group .top_post_item .post_cover .post_cover_info {
position: absolute;
top: 0;
width: 101%;
height: 100%;
opacity: 0;
background-color: rgba(0,0,0,0.7) !important;
transition: all 0.3s ease;
display: flex;
}
.top_post_group .top_post_item:hover .post_cover .post_cover_info{
opacity: 1;
}
.top_post_group .top_post_item .post_cover .post_cover_info .post_cover_text{
color: #fff;
padding: 12px 14px;
font-size: 15px;
font-weight: 400;
margin: 20px 0;
-webkit-line-clamp: 2;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
}
.top_post_group .top_post_item:hover .post_info,
.top_post_group .top_post_item:focus .post_info{
/*background: var(--mj-theme);*/
box-shadow: inset 0 -60px 0 0 var(--mj-theme);
}
.top_post_group .top_post_item .post_info a{
color: var(--mj-fontcolor) !important;
transition: 0;
}
.top_post_group .top_post_item:hover .post_info a{
color: var(--mj-white) !important;
}
.top_post_group .top_post_item .post_info {
padding: .2rem .5rem .3rem .5rem!important;
transition: .3s;
width: 100%;
height: 100%;
}
.top_post_group .top_post_item .post_info .article-title {
-webkit-line-clamp: 2;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
line-height: 1.4;
justify-content: center;
align-items: flex-end;
align-content: center;
font-weight: 600;
font-size: .8rem!important;
padding: 0!important;
}
2. 创建顶部轮播图

在themes/butterfly/layout/includes路径下创建sticky.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
link(rel='stylesheet' href='https://unpkg.com/swiper/swiper-bundle.min.css')
#sticky
#stickyList.swiper-container
#stickyWrapper.swiper-wrapper
.swiper-slide(onclick=`window.open('/random/','_self')`)
.grid-img
iframe#banner-page(src="<这里放iframe地址>" frameborder="0" loading="eager") // 可以放iframe
.grid-title
span 随便逛逛
i.fas.fa-arrow-right
.swiper-slide(onclick=`window.open('/video/','_self')`)
.grid-img
img.cover.entered.loaded(alt='VLOG' src='https://npm.elemecdn.com/justlovesmile-photo/myvlog.gif') // 可以放GIF
.grid-title
span 看看VLOG
i.fas.fa-arrow-right
.swiper-slide(onclick=`window.open('/music/','_self')`)
.grid-img
img.cover.entered.loaded(alt='歌单' src='https://npm.elemecdn.com/justlovesmile-img/gitar.jpg') // 可以放图片
.grid-title
span 听听音乐
i.fas.fa-arrow-right
//- 分页器
.swiper-pagination

.js-pjax
script(src='https://unpkg.com/swiper/swiper-bundle.min.js')
script(src='/js/sticky.js')
link(rel='stylesheet' href='/css/sticky.css')

2.2 创建sticky.js
在themes/butterfly/source/js路径下创建sticky.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var mySwiper = new Swiper('#stickyList', {
direction: 'horizontal',
speed: 600,
loop: true,
effect : 'fade',
loopPreventsSlide: false,
autoplay: {
delay: 20000,
},
mousewheel: false,
pagination: {
el: ".swiper-pagination",
dynamicBullets: true,
},
})
2.3 创建sticky.css

在themes/butterfly/source/css路径下创建sticky.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
:root{
--mj-white: #fff;
--mj-card-bg: #fff;
--mj-theme: #425AEF;
}
#sticky,
#stickyList,
#stickyWrapper{
width: 100%;
height: 100%;
}
.swiper-container#stickyList {
overflow: hidden;
}
#stickyList .swiper-slide {
background: var(--mj-card-bg);
position: relative;
border-radius: 12px;
transition: 0.3s;
width: 100%;
height: 100%;
}
#stickyList .swiper-slide .grid-img {
overflow: hidden;
height: 16.2rem;
}
#stickyList .swiper-slide .grid-img img {
transition: 0.3s;
object-fit: cover;
display: block;
width: 100%;
height: 100%;
}
#stickyList .swiper-slide:hover .grid-title{
opacity: .8;
cursor: pointer !important;
}
#stickyList .swiper-slide:hover .grid-img{
filter: blur(5px);
}
#stickyList .swiper-slide:hover .grid-title span,
#stickyList .swiper-slide:hover .grid-title i{
transform: translateX(0px);
transition: .5s;
}
#stickyList .swiper-slide .grid-title span,
#stickyList .swiper-slide .grid-title i{
transform: translateX(-100px);
transition: .5s;
}
#stickyList .swiper-slide .grid-title {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
overflow: hidden;
background: var(--mj-theme);
color: var(--mj-white);
padding-left: 1.5rem;
display: flex;
flex-direction: column;
justify-content: center;
opacity: 0;
transition: .5s;
}
#stickyList .swiper-slide .grid-title span {
font-size: 5rem;
font-weight: 700;
line-height: 5rem;
}
#stickyList .swiper-slide .grid-title i {
font-size: 4rem;
opacity: .6;
}
@media screen and (max-width: 768px) {
#sticky {
display: none;
}
}
3. 创建文章推荐卡片

在hexo\source_data\路径下创建slider.yml文件,最好准备6个推荐文章,例如:

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
#- cover: 封面图片链接
# timeline: '2020-10-01' # 日期,需要用''包裹
# link: 置顶文章链接,站内文章建议填相对链接
# title: 置顶文章标题
# description: 置顶文章描述
- cover: https://npm.elemecdn.com/justlovesmile-img/20200715201402.png
timeline: '2020-07-15'
link: /posts/c8972b63.html
title: 必看 | Hexo博客搭建超级指南
description: Hexo博客搭建全过程,环境部署,博客魔改等等...
- cover: https://npm.elemecdn.com/justlovesmile-img/090412-1557363852af44.jpg
timeline: '2020-04-09'
link: /posts/56163.html
title: Hexo博客 | 博客中能用到的代码(一)
description: 这篇文章介绍了如何使用font awesome图标字体库,使用动态图标,添加网页运行时间,全站变黑白,鼠标点击特效,网页标题的动态效果,网页樱花特效,鼠标触动音乐特效
- cover: https://npm.elemecdn.com/justlovesmile-img/095658-1562983018e455.jpg
timeline: '2020-04-09'
link: /posts/15391.html
title: Hexo博客 | 博客中能用到的代码(二)
description: 这篇文章介绍了如何添加旋转小人和每日诗句
- cover: https://npm.elemecdn.com/justlovesmile-img/20220331192754.png
timeline: '2022-03-31'
link: /posts/a806bebe.html
title: 推荐 | 计算机专业,大学课程「笔记归档」
description: 本文是博主本科期间的专业课程学习笔记的整理和归档,适合计算机专业的同学阅读。
- cover: https://npm.elemecdn.com/justlovesmile-img/20220318183107.png
timeline: '2022-03-18'
link: /posts/589ec011.html
title: 深度学习 | Detectron2使用指南
description: Detectron2是Facebook AI Research的检测和分割框架,其主要基于PyTorch实现,但具有更模块化设计,因此它是灵活且便于扩展的。
- cover: https://npm.elemecdn.com/justlovesmile-img/202109111517311.jpg
timeline: '2021-09-11'
link: /posts/865c56ba.html
title: 目标检测 | 常用数据集标注格式及生成脚本
description: 目标检测是计算机视觉任务中的一个重要研究方向,是计算机视觉的根本性问题之一,是其他诸多计算机视觉任务的基础以及前提。本文主要介绍了目标检测数据集的几种标注格式和转换代码。
3.2 css样式
见1.2中.top_post_group等样式类,不再赘述…

右键菜单

如果你已经看过我以前写的右键菜单功能了,那么这篇教程在食用的时候将会变得十分简单。

具体效果自行右键查看。

由于本教程需要修改的地方较多,集成度较高,可以自行选择其中部分功能,本教程代码资源来自Heo。

步骤

新建themes/butterfly/source/custom/rightmenu.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447


// 初始化函数
var rm = {};
var navFn = {
switchDarkMode: () => { // Switch Between Light And Dark Mode
const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
if (nowMode === 'light') {
activateDarkMode()
saveToLocal.set('theme', 'dark', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night, false, 2000)
} else {
activateLightMode()
saveToLocal.set('theme', 'light', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day, false, 2000)
}
// handle some cases
typeof utterancesTheme === 'function' && utterancesTheme();
typeof FB === 'object' && window.loadFBComment();
window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
}
}
// 私有函数
var Jay = {
// 检测显示模式
darkModeStatus: function () {
let theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
if (theme == 'light') {
$(".menu-darkmode-text").text("深色模式");
}else {
$(".menu-darkmode-text").text("浅色模式");
}
},
// 下载图片
downloadImage: function(imgsrc, name) { //下载图片地址和图片名
rm.hideRightMenu();
if (rm.downloadimging == false) {
rm.downloadimging = true;
btf.snackbarShow('正在下载中,请稍后',false,10000)
setTimeout(function(){
let image = new Image();
// 解决跨域 Canvas 污染问题
image.setAttribute("crossOrigin", "anonymous");
image.onload = function() {
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
let context = canvas.getContext("2d");
context.drawImage(image, 0, 0, image.width, image.height);
let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件
a.download = name || "photo"; // 设置图片名称
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
};
image.src = imgsrc;
btf.snackbarShow('图片已添加盲水印,请遵守版权协议');
rm.downloadimging = false;
}, "10000");
}else{
btf.snackbarShow('有正在进行中的下载,请稍后再试');
}
},
}

//禁止图片拖拽
rm.stopdragimg=$("img");
rm.stopdragimg.on("dragstart",function(){return false;});

// 显示菜单
rm.showRightMenu = function(isTrue, x=0, y=0){
let $rightMenu = $('#rightMenu');
$rightMenu.css('top',x+'px').css('left',y+'px');
if(isTrue){
$rightMenu.show();
stopMaskScroll()
}else{
$rightMenu.hide();
}
}

// 隐藏菜单
rm.hideRightMenu = function(){
rm.showRightMenu(false);
$('#rightmenu-mask').attr('style','display: none');
}

// 尺寸
var rmWidth = $('#rightMenu').width();
var rmHeight = $('#rightMenu').height();

// 重新定义尺寸
rm.reloadrmSize = function(){
rmWidth = $('#rightMenu').width();
rmHeight = $('#rightMenu').height();
}

// 获取点击的href
var domhref = '';
var domImgSrc = '';
var globalEvent = null;

// 监听右键初始化
window.oncontextmenu = function(event){
if(document.body.clientWidth > 768){
let pageX = event.clientX + 10; //加10是为了防止显示时鼠标遮在菜单上
let pageY = event.clientY;
// console.log(event);
//其他额外菜单
let $rightMenuOther = $('.rightMenuOther');
let $rightMenuPlugin = $('.rightMenuPlugin');
let $rightMenuCopyText = $('#menu-copytext');
let $rightMenuPasteText = $('#menu-pastetext');
let $rightMenuCommentText = $('#menu-commenttext');
let $rightMenuNewWindow = $('#menu-newwindow');
let $rightMenuCopyLink = $('#menu-copylink');
let $rightMenuCopyImg = $('#menu-copyimg');
let $rightMenuDownloadImg = $('#menu-downloadimg');
let $rightMenuSearch = $('#menu-search');
let $rightMenuSearchBaidu = $('#menu-searchBaidu');
let $rightMenuMusicToggle = $('#menu-music-toggle');
let $rightMenuMusicBack = $('#menu-music-back');
let $rightMenuMusicForward = $('#menu-music-forward');
let $rightMenuMusicPlaylist = $('#menu-music-playlist');
let $rightMenuMusicCopyMusicName = $('#menu-music-copyMusicName');
let href = event.target.href;
let imgsrc = event.target.currentSrc;

// 判断模式 扩展模式为有事件
let pluginMode = false;
$rightMenuOther.show();
globalEvent = event;

// 检查是否需要复制 是否有选中文本
if(selectTextNow && window.getSelection()){
pluginMode = true;
$rightMenuCopyText.show();
$rightMenuCommentText.show();
$rightMenuSearch.show();
$rightMenuSearchBaidu.show();
}else{
$rightMenuCopyText.hide();
$rightMenuCommentText.hide();
$rightMenuSearchBaidu.hide();
$rightMenuSearch.hide();
}

//检查是否右键点击了链接a标签
if(href){
pluginMode = true;
$rightMenuNewWindow.show();
$rightMenuCopyLink.show();
domhref = href;
}else{
$rightMenuNewWindow.hide();
$rightMenuCopyLink.hide();
}

//检查是否需要复制图片
if(imgsrc){
pluginMode = true;
$rightMenuCopyImg.show();
$rightMenuDownloadImg.show();
domImgSrc = imgsrc;
}else{
$rightMenuCopyImg.hide();
$rightMenuDownloadImg.hide();
}

// 判断是否为输入框
if (event.target.tagName.toLowerCase() === 'input' || event.target.tagName.toLowerCase() === 'textarea') {
console.log('这是一个输入框')
pluginMode = true;
$rightMenuPasteText.show();
}else{
$rightMenuPasteText.hide();
}

//判断是否是音乐
if (event.target.nodeName == "METING-JS") {
console.log('这是一个音乐');
pluginMode = true;
$rightMenuMusicToggle.show();
$rightMenuMusicBack.show();
$rightMenuMusicForward.show();
$rightMenuMusicPlaylist.show();
$rightMenuMusicCopyMusicName.show();
}else {
$rightMenuMusicToggle.hide();
$rightMenuMusicBack.hide();
$rightMenuMusicForward.hide();
$rightMenuMusicPlaylist.hide();
$rightMenuMusicCopyMusicName.hide()
}
// 如果不是扩展模式则隐藏扩展模块
if (pluginMode){
$rightMenuOther.hide();
$rightMenuPlugin.show();
}else{
$rightMenuPlugin.hide()
}

rm.reloadrmSize()

// 鼠标默认显示在鼠标右下方,当鼠标靠右或考下时,将菜单显示在鼠标左方\上方
if(pageX + rmWidth > window.innerWidth){
pageX -= rmWidth+10;
}
if(pageY + rmHeight > window.innerHeight){
pageY -= pageY + rmHeight - window.innerHeight;
}

rm.showRightMenu(true, pageY, pageX);
$('#rightmenu-mask').attr('style','display: flex');
return false;
}
};

// 下载图片状态
rm.downloadimging = false;

// 复制图片到剪贴板
rm.writeClipImg = function (imgsrc) {
console.log('按下复制');
rm.hideRightMenu();
btf.snackbarShow('正在下载中,请稍后',false,10000)
if(rm.downloadimging == false){
rm.downloadimging = true;
setTimeout(function(){
copyImage(imgsrc);
btf.snackbarShow('复制成功!图片已添加盲水印,请遵守版权协议');
rm.downloadimging = false;
},"10000")
}
}

function imageToBlob(imageURL) {
const img = new Image;
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
img.crossOrigin = "";
img.src = imageURL;
return new Promise(resolve => {
img.onload = function () {
c.width = this.naturalWidth;
c.height = this.naturalHeight;
ctx.drawImage(this, 0, 0);
c.toBlob((blob) => {
// here the image is a blob
resolve(blob)
}, "image/png", 0.75);
};
})
}

async function copyImage(imageURL){
const blob = await imageToBlob(imageURL)
const item = new ClipboardItem({ "image/png": blob });
navigator.clipboard.write([item]);
}

rm.switchDarkMode = function() {
navFn.switchDarkMode();
rm.hideRightMenu();
Jay.darkModeStatus();
}

rm.copyUrl = function(id) {
$("body").after("<input id='copyVal'></input>");
var text = id;
var input = document.getElementById("copyVal");
input.value = text;
input.select();
input.setSelectionRange(0, input.value.length);
document.execCommand("copy");
$("#copyVal").remove();
}

function stopMaskScroll(){
if (document.getElementById("rightmenu-mask")){
let xscroll = document.getElementById("rightmenu-mask");
xscroll.addEventListener("mousewheel", function (e) {
//阻止浏览器默认方法
rm.hideRightMenu();
// e.preventDefault();
}, false);
}
if (document.getElementById("rightMenu")){
let xscroll = document.getElementById("rightMenu");
xscroll.addEventListener("mousewheel", function (e) {
//阻止浏览器默认方法
rm.hideRightMenu();
// e.preventDefault();
}, false);
}
}

rm.rightmenuCopyText = function(txt){
if (navigator.clipboard) {
navigator.clipboard.writeText(txt);
}
rm.hideRightMenu();
}

rm.copyPageUrl = function(){
var url = window.location.href;
rm.copyUrl(url);
btf.snackbarShow('复制本页链接地址成功',false,2000);
rm.hideRightMenu();
}

rm.sharePage = function(){
var content = window.location.href;
rm.copyUrl(url);
btf.snackbarShow('复制本页链接地址成功',false,2000);
rm.hideRightMenu();
}

// 复制当前选中文本
var selectTextNow = '';
document.onmouseup = document.ondbclick= selceText;
function selceText(){
var txt;
if(document.selection){
txt = document.selection.createRange().text;
}else{
txt = window.getSelection()+'';
}
if(txt){
selectTextNow = txt;
// console.log(selectTextNow);
}else{
selectTextNow = '';
}
}

// 读取剪切板
rm.readClipboard = function(){
if (navigator.clipboard) {
navigator.clipboard.readText().then(clipText => rm.insertAtCaret(globalEvent.target, clipText) );
}
}

// 粘贴文本到焦点
rm.insertAtCaret = function(elemt, value){
const startPos = elemt.selectionStart,
endPos = elemt.selectionEnd;
if (document.selection) {
elemt.focus();
var sel = document.selection.createRange();
sel.text = value;
elemt.focus();
} else {
if (startPos || startPos == '0') {
var scrollTop = elemt.scrollTop;
elemt.value = elemt.value.substring(0, startPos) + value + elemt.value.substring(endPos, elemt.value.length);
elemt.focus();
elemt.selectionStart = startPos + value.length;
elemt.selectionEnd = startPos + value.length;
elemt.scrollTop = scrollTop;
} else {
elemt.value += value;
elemt.focus();
}
}
}

//粘贴文本
rm.pasteText = function(){
const result = rm.readClipboard() || '';
rm.hideRightMenu();
}

//引用到评论
rm.rightMenuCommentText = function(txt){
rm.hideRightMenu();
var input = document.getElementsByClassName('el-textarea__inner')[0];
let evt = document.createEvent('HTMLEvents');
evt.initEvent('input', true, true);
let inputValue = replaceAll(txt,'\n','\n> ')
input.value = '> ' + inputValue + '\n\n';
input.dispatchEvent(evt);
var domTop = document.querySelector("#post-comment").offsetTop;
window.scrollTo(0,domTop - 80);
input.focus();
input.setSelectionRange(-1,-1);
if (document.getElementById("comment-tips")) {
document.getElementById("comment-tips").classList.add("show");
}
}

//替换所有内容
function replaceAll(string, search, replace) {
return string.split(search).join(replace);
}

// 百度搜索
rm.searchBaidu = function(){
btf.snackbarShow('即将跳转到百度搜索',false,2000);
setTimeout(function(){
window.open('https://www.baidu.com/s?wd=' + selectTextNow);
}, "2000");
rm.hideRightMenu();
}

//分享链接
rm.copyLink = function(){
rm.rightmenuCopyText(domhref);
btf.snackbarShow('已复制链接地址');
}

function addRightMenuClickEvent(){
// 添加点击事件
$('#menu-backward').on('click',function(){window.history.back();rm.hideRightMenu();});
$('#menu-forward').on('click',function(){window.history.forward();rm.hideRightMenu();});
$('#menu-refresh').on('click',function(){window.location.reload();});
$('#menu-top').on('click',function(){btf.scrollToDest(0, 500);rm.hideRightMenu();});
$('.menu-link').on('click',rm.hideRightMenu);
$('#menu-darkmode').on('click',rm.switchDarkMode);
$('#menu-home').on('click',function(){window.location.href = window.location.origin;});
$('#menu-randomPost').on('click',function(){toRandomPost()});
$('#menu-commentBarrage').on('click',Jay.switchCommentBarrage);
$('#rightmenu-mask').on('click',rm.hideRightMenu);
$('#rightmenu-mask').contextmenu(function(){
rm.hideRightMenu();
return false;
});
$('#menu-translate').on('click',function(){
rm.hideRightMenu();
translateInitialization();
});
$('#menu-copy').on('click', rm.copyPageUrl);
$('#menu-pastetext').on('click',rm.pasteText);
$('#menu-copytext').on('click',function(){rm.rightmenuCopyText(selectTextNow);btf.snackbarShow('复制成功,复制和转载请标注本文地址');});
$('#menu-commenttext').on('click',function(){rm.rightMenuCommentText(selectTextNow);});
$('#menu-newwindow').on('click',function(){window.open(domhref);rm.hideRightMenu();});
$('#menu-copylink').on('click',rm.copyLink);
$('#menu-downloadimg').on('click',function(){Jay.downloadImage(domImgSrc,'Jay');});
$('#menu-copyimg').on('click',function(){rm.writeClipImg(domImgSrc);});
$('#menu-searchBaidu').on('click',rm.searchBaidu);
//音乐
$('#menu-music-toggle').on('click',Jay.musicToggle);
$('#menu-music-back').on('click',Jay.musicSkipBack);
$('#menu-music-forward').on('click',Jay.musicSkipForward);
$('#menu-music-copyMusicName').on('click',function(){rm.rightmenuCopyText(Jay.musicGetName());btf.snackbarShow('复制歌曲名称成功',false,3000);});
}

新建themes/butterfly/layout/includes/rightmenu.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
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
.js-pjax
#rightMenu
.rightMenu-group.rightMenu-small
.rightMenu-item#menu-backward
i.fa-solid.fa-arrow-left
.rightMenu-item#menu-forward
i.fa-solid.fa-arrow-right
.rightMenu-item#menu-refresh
i.fa-solid.fa-arrow-rotate-right
.rightMenu-item#menu-top
i.fa-solid.fa-arrow-up
.rightMenu-group.rightMenu-line.rightMenuPlugin
.rightMenu-item#menu-copytext
i.fas.fa-copy
span 复制选中文本
.rightMenu-item#menu-pastetext
i.fas.fa-paste
span 粘贴文本
a.rightMenu-item#menu-commenttext
i.fas.fa-comment-medical
span 引用到评论
.rightMenu-item#menu-newwindow
i.fas.fa-window-restore
span 新窗口打开
.rightMenu-item#menu-copylink
i.fas.fa-link
span 复制链接地址
.rightMenu-item#menu-copyimg
i.fas.fa-images
span 复制此图片
.rightMenu-item#menu-downloadimg
i.fas.fa-download
span 下载此图片
.rightMenu-item#menu-search
i.fa-solid.fa-magnifying-glass
span 站内搜索
.rightMenu-item#menu-searchBaidu
i.fa-solid.fa-magnifying-glass
span 百度搜索
.rightMenu-group.rightMenu-line.rightMenuOther
a.rightMenu-item.menu-link#menu-randomPost
i.fas.fa-shuffle
span 随便逛逛
a.rightMenu-item.menu-link(href='/categories/')
i.fas.fa-cube
span 博客分类
a.rightMenu-item.menu-link(href='/tags/')
i.fas.fa-tags
span 文章标签
.rightMenu-group.rightMenu-line
a.rightMenu-item.menu-link(href='/privacy/')
i.fa-solid.fa-hand
span 隐私协议
a.rightMenu-item.menu-link(href='/cc/')
i.fa-solid.fa-closed-captioning
span 版权协议
.rightMenu-group.rightMenu-line.rightMenuOther
.rightMenu-item#menu-copy
i.fas.fa-copy
span 复制地址
.rightMenu-item#menu-darkmode
i.fa-solid.fa-moon
span.menu-darkmode-text 显示模式
.rightMenu-item#menu-translate
i.fas.fa-language
span 轉為繁體
#rightmenu-mask

在themes/butterfly/layout/includes/layout.pug文件中引入上述文件

1
2
3
4
5
6
7
8
9
    else
include ./404.pug

include ./rightside.pug
!=partial('includes/third-party/search/index', {}, {cache: true})
//- 引入右键
+ include ./rightmenu.pug
include ./additional-js.pug
在自己创建的自定义css文件中引入右键菜单样式,没有的可以新建themes/butterfly/source/custom/custom.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
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

#rightMenu {
display: none;
position: fixed;
padding: 0 0.25rem;
width: 9rem;
height: fit-content;
top: 10%;
left: 10%;
background-color: var(--Jay-maskbgdeep);
-webkit-backdrop-filter: blur(20px);
backdrop-filter: blur(20px);
color: var(--Jay-fontcolor);
border-radius: 12px;
z-index: 99994;
border: var(--style-border);
user-select: none;
box-shadow: var(--Jay-shadow-black);
}


#rightMenu:hover {
border: var(--style-border-hover);
box-shadow: var(--Jay-shadow-theme);
}

#rightMenu .rightMenu-group {
padding: 0.35rem 0.3rem;
transition: 0.3s;
}

#rightMenu .rightMenu-line {
border-top: 1px dashed var(--Jay-theme-op);
}

#rightMenu .rightMenu-group.rightMenu-small {
display: flex;
justify-content: space-between;
}

#rightMenu .rightMenu-group .rightMenu-item {
border-radius: 8px;
transition: 0.3s;
cursor: pointer;
}

#rightMenu .rightMenu-line .rightMenu-item {
margin: 0.25rem 0;
padding: 0.25rem 0;
}

#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item {
display: flex;
}

#rightMenu .rightMenu-group .rightMenu-item:hover {
background-color: var(--Jay-main);
color: var(--Jay-white);
box-shadow: var(--Jay-shadow-main);
}

#rightMenu .rightMenu-group .rightMenu-item:active {
transform: scale(0.97);
}

#rightMenu .rightMenu-group .rightMenu-item i {
display: inline-block;
text-align: center;
line-height: 1.5rem;
width: 1.5rem;
padding: 0 0.25rem;
}

#rightMenu .rightMenu-line .rightMenu-item i {
margin: 0 0.25rem;
}

#rightMenu .rightMenu-group .rightMenu-item span {
line-height: 1.5rem;
}

.rightMenu-small .rightMenu-item {
width: 30px;
height: 30px;
line-height: 30px;
}

#rightmenu-mask {
position: fixed;
width: 100vw;
height: 100vh;
background: none;
top: 0;
left: 0;
display: none;
z-index: 101;
margin: 0 !important;
z-index: 99993;
}

引入右键菜单js,如果是以前没有新建过css的,需要引入自定义css

1
2
3
4
5
6
7
8
inject:
head:
# - <link rel="stylesheet" href="">
# 没有引入的需要引入,如果引入过就不需要了
- <link rel="stylesheet" href="/custom/custom.css">

bottom:
- <script data-pjax='' src="/custom/rightmenu.js"></script>

至此,大部分都完成了,但是你可能会发现无法实现翻译功能,无法实现右键站内搜索,如果不需要这些功能的就不需要往下看了。

进阶

由于此部分需要修改源码,可以自行选择。

站内搜索只针对开启了Algolia的用户,本地的写法一样参考自行修改

右键翻译

修改themes/butterfly/source/js/tw_cn.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  function translatePage () {
if (targetEncoding === 1) {
currentEncoding = 1
targetEncoding = 2
translateButtonObject.innerHTML = msgToTraditionalChinese
saveToLocal.set(targetEncodingCookie, targetEncoding, 2)
translateBody()
if (isSnackbar) btf.snackbarShow(snackbarData.cht_to_chs)
} else if (targetEncoding === 2) {
currentEncoding = 2
targetEncoding = 1
translateButtonObject.innerHTML = msgToSimplifiedChinese
saveToLocal.set(targetEncodingCookie, targetEncoding, 2)
translateBody()
if (isSnackbar) btf.snackbarShow(snackbarData.chs_to_cht)
}
+ rm.hideRightMenu();
}

修改引入资源路径

1
2
3
4
5
6
7
8
9
10
11
CDN:
# The CDN provider of internal scripts (主题内部 js 的 cdn 配置)
# option: local/jsdelivr/unpkg/cdnjs/custom
# Dev version can only choose. ( dev版的主题只能设置为 local )
internal_provider: custom #local
...
option:
# main_css:
# main:
# utils:
translate: /js/tw_cn.js

至此,实现右键菜单翻译功能。

右键搜索

修改source/js/search/algolia.js文件,大致在27行的位置(如果是4.3.0版本,其他暂不清楚)

1
2
3
4
5
6
7
8
9
10
11
12
const searchClickFn = () => {
document.querySelector('#search-button > .search').addEventListener('click', openSearch)
+ $('#menu-search').on('click',function(){
+ rm.hideRightMenu();
+ openSearch();
+ let t=document.getElementsByClassName('ais-search-box--input')[0];
+ let evt = document.createEvent('HTMLEvents');
+ evt.initEvent('input', true, true);
+ t.value=selectTextNow;
+ t.dispatchEvent(evt);
+ });
}

修改引入资源路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CDN:

# The CDN provider of internal scripts (主题内部 js 的 cdn 配置)
# option: local/jsdelivr/unpkg/cdnjs/custom
# Dev version can only choose. ( dev版的主题只能设置为 local )
internal_provider: custom #local
...
option:
# main_css:
# main:
# utils:
translate: /js/tw_cn.js
# local_search:
algolia_js: /js/search/algolia.js

加载动画

修改 themes/butterfly/layout/includes/loading/fullpage-loading.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

#loading-box(onclick='document.getElementById("loading-box").classList.add("loaded")')
.loading-bg
div.loading-img
.loading-image-dot

script.
const preloader = {
endLoading: () => {
document.body.style.overflow = 'auto';
document.getElementById('loading-box').classList.add("loaded")
},
initLoading: () => {
document.body.style.overflow = '';
document.getElementById('loading-box').classList.remove("loaded")

}
}
window.addEventListener('load',()=> { preloader.endLoading() })

if (!{theme.pjax && theme.pjax.enable}) {
document.addEventListener('pjax:send', () => { preloader.initLoading() })
document.addEventListener('pjax:complete', () => { preloader.endLoading() })
}

修改themes/butterfly/layout/includes/loading/index.pug

1
2
3
4
5
6
7
if theme.preloader.source === 1
include ./fullpage-loading.pug
else if theme.preloader.source === 2
include ./pace.pug
else
include ./fullpage-loading.pug
include ./pace.pug

新建source/css/progress_bar.css, 也可以不做这一步下面配置文件pace_css_url这一项就要留空, 这一步是修改 pace 加载的胶囊 💊 样式用的

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
.pace {
-webkit-pointer-events: none;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
z-index: 2000;
position: fixed;
margin: auto;
top: 10px;
left: 0;
right: 0;
height: 8px;
border-radius: 8px;
width: 4rem;
background: #eaecf2;
border: 1px #e3e8f7;
overflow: hidden;
}

.pace-inactive .pace-progress {
opacity: 0;
transition: 0.3s ease-in;
}

.pace .pace-progress {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
max-width: 200px;
position: absolute;
z-index: 2000;
display: block;
top: 0;
right: 100%;
height: 100%;
width: 100%;
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
animation: gradient 1.5s ease infinite;
background-size: 200%;
}

.pace.pace-inactive {
opacity: 0;
transition: 0.3s;
top: -8px;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}

修改themes/butterfly/source/css/_layout/loading.styl, 注意其中颜色代码--anzhiyu-card-bg等需自行替换为自己的色值。

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

if hexo-config('preloader')
.loading-bg
display: flex;
width: 100%;
height: 100%;
position: fixed;
background: var(--anzhiyu-card-bg);
z-index: 1001;
opacity: 1;
transition: .3s;

#loading-box
.loading-img
width: 100px;
height: 100px;
border-radius: 50%;
margin: auto;
border: 4px solid #f0f0f2;
animation-duration: .3s;
animation-name: loadingAction;
animation-iteration-count: infinite;
animation-direction: alternate;
.loading-image-dot
width: 30px;
height: 30px;
background: #6bdf8f;
position: absolute;
border-radius: 50%;
border: 6px solid #fff;
top: 50%;
left: 50%;
transform: translate(18px, 24px);
&.loaded
.loading-bg
opacity: 0;
z-index: -1000;

@keyframes loadingAction
0% {
opacity: 1;
}

100% {
opacity: .4;
}
1
2
3
4
.loading-img {
background: url(https://npm.elemecdn.com/anzhiyu-blog@2.1.1/img/avatar.webp) no-repeat center center;
background-size: cover;
}

最后修改_config.butterfly.ymlpreloader选项, 改完以后source: 1为满屏加载无pace胶囊,source: 2pace胶囊无满屏动画, source: 3是两者都启用。

1
2
3
4
5
6
7
8
9
10
# Loading Animation (加载动画)
preloader:
enable: true
# source
# 1. fullpage-loading
# 2. pace (progress bar)
# else all
source: 3
# pace theme (see https://codebyzach.github.io/pace/)
pace_css_url: /css/progress_bar.css