阅读本篇前,请先阅读前几篇文章:
基于 Hexo 从零开始搭建个人博客(一)
基于 Hexo 从零开始搭建个人博客(二)
基于 Hexo 从零开始搭建个人博客(三)
基于 Hexo 从零开始搭建个人博客(四)
基于 Hexo 从零开始搭建个人博客(五)

前言

本站基于Hexo搭建,用的 🦋 hexo-theme-butterfly 主题,已经升级到 v4.7.0 。 请注意最新的🦋 hexo-theme-butterfly 版本已经更新到 v4.8.1

如果你是 v3.7.1 的版本,请移步 v3.7.1 站点进行浏览。

注意:我的博客根目录路径为 【G:/hexo-blog/blog-demo】,下文所说的根目录都是此路径,将用[BlogRoot]代替。如果不清楚根目录路径,请回到教程 基于 Hexo 从零开始搭建个人博客(二),查看你执行hexo init xxx这条命令时所选择的路径,例如我选择的路径是【G:/hexo-blog】,我的博客根目录即为【G:/hexo-blog/xxx】。

修改站点配置文件_config.yml,路径为【BlogRoot/_config.yml】。

修改主题配置文件_config.butterfly.yml,路径为【BlogRoot/_config.butterfly.yml】。

Butterfly主题美化

生成文章唯一链接

Hexo的默认文章链接格式是年,月,日,标题这种格式来生成的。如果你的标题是中文的话,那你的URL链接就会包含中文。

1
permalink: :year/:month/:day/:title
  1. 前往你的Hexo博客根目录,打开cmd命令窗口执行npm install hexo-abbrlink --save
    1
    npm install hexo-abbrlink --save
  2. 修改站点配置文件_config.ymlpermalink属性。
    1
    2
    3
    4
    5
    6
    - permalink: :year/:month/:day/:title/
    #修改为
    permalink: post/:abbrlink.html # post为自定义前缀
    abbrlink:
    alg: crc32 #算法: crc16(default) and crc32
    rep: hex #进制: dec(default) and hex
效果预览
查看步骤

编辑BlogRoot/themes/butterfly/layout/includes/footer.pug文件,

将以下内容

1
©${theme.footer.owner.since} - ${nowYear} By ${config.author}

改为

1
&copy;${theme.footer.owner.since} - ${nowYear + ' '} <i id="heartbeat" class="fa fas fa-heartbeat"></i> ${config.author}

将以下内容

1
&copy;${nowYear} By ${config.author} 

改为

1
&copy;${nowYear + ' '} <i id="heartbeat" class="fa fas fa-heartbeat"></i> ${config.author}

将以下内容添加到 <head></head>标签内:

1
<link rel="stylesheet" href="https://fastly.jsdelivr.net/gh/HCLonely/images@master/others/heartbeat.min.css">

具体放置位置,可以参考下图:

修改标题样式

效果预览
回形针
回形针
旋转风车
旋转风车
查看步骤

BlogRoot/themes/butterfly/source/css文件下新建 css 文件,并命名为 custom.css(命名按照自己喜好去命名,只需在主题配置文件_config.butterfly.yml中引入对应的css文件即可),将以下代码复制到新建的custom.css中。

如果想自行修改标题样式的话,将content: '\f0c1';中的内容换成自己想要的即可,如要添加动画,参考animation: avatar_turn_around 1s linear infinite;

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
#article-container h1:before,
#article-container h2:before,
#article-container h3:before,
#article-container h4:before,
#article-container h5:before,
#article-container h6:before,
#post .post-outdate-notice:before,
.fontawesomeIcon,
.note:not(.no-icon)::before,
hr:before {
display: inline-block;
font-weight: 600;
font-style: normal;
font-variant: normal;
font-family: 'Font Awesome 5 Free';
text-rendering: auto;
-webkit-font-smoothing: antialiased
}
#article-container h1:before,
#article-container h2:before,
#article-container h3:before,
#article-container h4:before,
#article-container h5:before,
#article-container h6:before {
position: absolute;
color: #f47466;
/* 回形针 */
content: '\f0c1';
line-height: 1;
-webkit-transition: all .2s ease-out;
-moz-transition: all .2s ease-out;
-o-transition: all .2s ease-out;
-ms-transition: all .2s ease-out;
transition: all .2s ease-out;
/* 若要使用风车效果,请去掉下面的注释 */
/* content: '\f863';
animation: avatar_turn_around 1s linear infinite; */
}
#article-container h1 {
padding-left: 1.4rem
}

#article-container h1 code {
font-size: 1rem
}

#article-container h1:before {
margin-left: -1.3rem;
top: calc(50% - .5rem);
font-size: 1rem
}

#article-container h1:hover {
padding-left: 1.6rem
}

#article-container h2 {
padding-left: 1.3rem
}

#article-container h2 code {
font-size: .9rem
}

#article-container h2:before {
margin-left: -1.4rem;
top: calc(50% - .45rem);
font-size: .9rem
}

#article-container h2:hover {
padding-left: 1.5rem
}

#article-container h3 {
padding-left: 1.2rem
}

#article-container h3 code {
font-size: .8rem;
top: calc(50% - .4rem);

}

#article-container h3:before {
margin-left: -1.2rem;
top: calc(50% - .4rem);
font-size: .8rem
}

#article-container h3:hover {
padding-left: 1.4rem
}

#article-container h4 {
padding-left: 1.1rem
}

#article-container h4 code {
font-size: .7rem
}

#article-container h4:before {
margin-left: -1rem;
top: calc(50% - .35rem);
font-size: .7rem
}

#article-container h4:hover {
padding-left: 1.3rem
}

#article-container h5 {
padding-left: 1rem
}

#article-container h5 code {
font-size: .6rem
}

#article-container h5:before {
margin-left: -.8rem;
top: calc(50% - .3rem);
font-size: .6rem
}

#article-container h5:hover {
padding-left: 1.2rem
}

#article-container h6 {
padding-left: 1rem
}

#article-container h6 code {
font-size: .6rem
}

#article-container h6:before {
margin-left: -.8rem;
top: calc(50% - .3rem);
font-size: .6rem
}

#article-container h6:hover {
padding-left: 1.2rem
}

添加豆瓣插件

此方法可能不再适用:node 版本过高导致,可以下个 nvm 来控制 node 版本,建议安装较低的 node 版本(推荐v12.18.0)

前往博客根目录,打开cmd命令窗口执行npm install hexo-douban --save

1
npm install hexo-douban --save

修改站点配置文件_config.yml,添加如下代码:

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
douban:
id: 228172215
builtin: false
item_per_page: 10
book:
path: books/index.html
title: 'This is my book title'
quote: 'This is my book quote'
option:
movie:
path: movies/index.html
title: 'This is my movie title'
quote: 'This is my movie quote'
option:
game:
path: games/index.html
title: 'This is my game title'
quote: 'This is my game quote'
option:
song:
path: songs/index.html
title: 'This is my song title'
quote: 'This is my song quote'
option:
timeout: 10000
  • id: 你的豆瓣ID(纯数字格式,不是自定义的域名)。获取方法可以参考 怎样获取豆瓣的数字 ID
  • builtin: 是否将 hexo douban 命令默认嵌入进 hexo g、hexo s,使其自动执行 hexo douban 命令。默认关闭。当你的豆瓣条目较多时,也建议关闭。
  • item_per_page: 每页展示的条目数,默认 10 。
  • path: 生成页面后的路径,默认生成在 //my-blog/books/index.html 等下面。如需自定义路径,则可以修改这里。
  • title: 该页面的标题。
  • quote: 写在页面开头的一段话,支持 html 语法。
  • option: 该页面额外的 Front-matter 配置,参考 Hexo 文档。无特别需要,留空即可。
  • timeout: 爬取数据的超时时间,默认是 10000ms ,如果在使用时发现报了超时的错(ETIMEOUT)可以把这个数据设置的大一点。

在主题配置文件_config.butterfly.yml中配置以下内容:

1
2
3
4
5
6
# 如果你有使用hexo-douban,可配置這個
douban:
meta: true
movies_img: https://fastly.jsdelivr.net/gh/jerryc127/butterfly_cdn@2.1.0/top_img/movie.jpg
books_img: https://fastly.jsdelivr.net/npm/blog-gallery@1.0.0/1/20200206161657.webp
# games_img:

前往博客根目录,打开cmd命令窗口执行hexo douban

1
hexo douban

等待命令执行完毕,出现下图所示内容即为成功。

请注意,我的butterfly主题版本不是最新的,导航菜单栏格式请按照最新的格式写。

如下图:

添加访客地图

效果预览
查看步骤

前往 clustrmaps 网站注册一个帐号。

找到Free Tools下面的Website Widget, 点击Get Map Widget

输入你的博客网址,点击Next

根据你自己的喜好选择样式Map widgetGlobe Widget(本人使用后者)。

找到如下代码,记住 src (****** 的部分):

1
<script type="text/javascript" id="clstr_globe" src="**********************">

BlogRoot/themes/butterfly/layout/includes/widget文件夹新建card_map.pug文件,文件内容如下:

1
2
3
4
5
6
.card-widget.card-map
.card-content
.item-headline
i.fa.fa-globe-asia(aria-hidden="true")
span= _p('aside.card_map')
script#clstr_globe(type="text/javascript" defer="defer" src="此处填入你自己的代码")

编辑 BlogRoot/themes/butterfly/layout/includes/widget/index.pug文件,在你想要显示的位置插入以下代码(注意格式):

1
2
if theme.aside.card_map
!=partial('includes/widget/card_map', {}, {cache:true})

具体放置位置,可以参考下图:

编辑主题配置文件_config.butterfly.yml,在card_webinfo下面添加一行card_map: true

编辑BlogRoot/themes/butterfly/languages/zh-CN.yml文件 (请根据你的网站语言选择),找到card_announcement: 公告 , 在下面添加一行card_map: 访客地图 (后面的文本可自定义),繁体字方法一样,修改BlogRoot/themes/butterfly/languages/zh-TW.yml文件就行。

如果不想显示,直接把主题配置文件_config.butterfly.yml中的card_map: true 改为 card_map: false 即可。

添加Pixiv日榜

效果预览
查看步骤
  1. BlogRoot/themes/butterfly/layout/includes/widget文件夹新建 card_pixiv.pug文件,文件内容如下:

    1
    2
    3
    4
    5
    6
    .card-widget.card-pixiv
    .card-content
    .item-headline
    i.fa.fa-image(aria-hidden="true")
    span= _p('aside.card_pixiv')
    iframe(src="https://cloud.mokeyjay.com/pixiv" frameborder="0" style="width:99%;height:380px;margin:0;")

    https://cloud.mokeyjay.com/pixiv 使用的是 超能小紫 提供的服务,也可以自行搭建,搭建方式请看这里

  2. 编辑BlogRoot/themes/butterfly/layout/includes/widget/index.pug 文件,在你想要显示的位置插入以下代码:

    1
    2
    if theme.aside.card_pixiv
    !=partial('includes/widget/card_pixiv', {}, {cache:true})
  3. 编辑主题配置文件_config.butterfly.yml,在 card_webinfo 下面添加一行 card_pixiv: true,可以通过搜索关键词 aside,找到对应位置添加即可。不想显示,直接把文件中的 card_pixiv: true 改为 card_pixiv: false 即可。

  4. 编辑 BlogRoot/themes/butterfly/languages/zh-CN.yml文件 (请根据你的网站语言选择),找到card_announcement: 公告,在下面添加一行card_pixiv: Pixiv日榜Top50(后面的文本可自定义)。

哔哩哔哩番剧页面插件

效果预览
查看步骤
关于图片加载相关问题

懒加载问题,此插件懒加载可能与你主题的懒加载存在冲突,以下为几种解决方法:

1.全站关闭懒加载,此插件启用/不启用懒加载均可正常运行;
2.如果主题提供单独页面的懒加载配置参数,可在插件配置的extra_option中配置为关。
3.[建议]关闭此插件的懒加载,并按照主题的懒加载图片格式配置srcValue和lazyloadAttrName,例butterfly主题:

1
2
3
4
5
6
bangumi:
enable: true
...
lazyload: false
srcValue: '__image__'
...

更多详情可见:关于图片加载相关问题

  1. 安装依赖

    1
    npm install hexo-bilibili-bangumi --save
  2. 更新依赖库

    1
    npm install hexo-bilibili-bangumi --update --save
  3. 注入哔哩哔哩番剧
    修改站点配置文件_config.yml,添加如下代码:

    1
    2
    3
    4
    5
    6
    7
    bangumi:
    enable: true
    vmid: 321638084
    title: '生命不息,追番不止。'
    quote: 'Where there is life, there is life.'
    show: 1
    loading: '/img/bangumi-loading.gif'

    配置说明

    • enable: 是否启用
    • vmid: 哔哩哔哩番剧页面的 vmid(uid), 如何获取
    • title: 该页面的标题
    • quote: 写在页面开头的一段话,支持 html 语法
    • show: 初始显示页面:0: 想看 , 1: 在看 , 2: 看过,默认为 1
    • loading: 图片加载完成前的 loading 图片
  4. 执行Docs命令
    前往博客根目录,打开cmd命令窗口执行hexo new page bangumis

    1
    hexo new page bangumis

    找到 BlogRoot/source/bangumis/index.md 这个文件,修改这个文件,添加 type: "bangumis"

    1
    2
    3
    4
    5
    ---
    title: bangumis
    date: 2020-12-14 14:43:39
    type: "bangumis"
    ---

    防止请求次数过多插件不再自动获取番剧数据,所以请根据自己的需要在hexo generatehexo deploy之前使用hexo bangumi -u命令更新番剧数据。
    删除数据命令: hexo bangumi -d

  5. 获取 uid
    登录哔哩哔哩后前往 https://space.bilibili.com/xxx,网址最后的一串数字就是 uid。

添加卡通人物(看板娘)

效果预览
查看步骤

前往博客根目录,打开cmd命令窗口执行npm install --save hexo-helper-live2d

1
npm install --save hexo-helper-live2d

输入以下命令,下载相应的模型, 替换成你想要的模型名称即可,更多模型选择请点击此处,各个模型的预览请访问原作者

1
npm install --save live2d-widget-model-shizuku

修改站点配置文件_config.yml,添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
live2d:
enable: true
scriptFrom: local # 默认
tagMode: false # 标签模式, 是否仅替换 live2d tag标签而非插入到所有页面中
debug: false # 调试, 是否在控制台输出日志
model:
use: live2d-widget-model-shizuku #模型选择
display:
position: right #模型位置
width: 150 #模型宽度
height: 300 #模型高度
hOffset: 20
vOffset: -20
mobile:
show: false #是否在手机端显示

重新编译运行,即可看到效果。

添加全局吸底APlayer

参考链接:Butterfly添加全局吸底Aplayer教程
此步骤适用于安装了hexo-tag-aplayer插件的人

效果预览
查看步骤
  1. 前往博客根目录,打开cmd命令窗口执行以下命令:

    1
    npm i hexo-tag-aplayer --save
  2. 关闭asset_inject
    由于需要全局都插入 aplayer 和 meting 资源,为了防止插入重复的资源,需要把 asset_inject 设为false
    修改站点配置文件_config.yml,配置以下内容:

    1
    2
    3
    aplayer:
    meting: true
    asset_inject: false
  3. 开启主题的aplayerInject
    修改主题配置文件_config.butterfly.yml,将enable设为trueper_page设为true

    1
    2
    3
    4
    # Inject the css and script (aplayer/meting)
    aplayerInject:
    enable: true
    per_page: true
  4. 插入Aplayer html
    为了适配hexo-tag-aplayer,主题内置的Meting js仍为1.2版本,并非最新的2.x版本。
    Aplayer html 例子(示例中没有显示歌词):

    1
    <div class="aplayer no-destroy" data-id="7427714271" data-server="netease" data-type="playlist" data-fixed="true" data-mini="true" data-listFolded="false" data-order="random" data-lrctype="1" data-preload="none" data-autoplay="true" muted></div>

    参数解释如下表:

    optiondefaultdescription
    data-idrequiresong id / playlist id / album id / search keyword
    data-serverrequiremusic platform: netease, tencent, kugou, xiami, baidu
    data-typerequiresong, playlist, album, search, artist
    data-fixedfalseenable fixed mode
    data-minifalseenable mini mode
    data-autoplayfalseaudio autoplay
    data-theme#2980b9main color
    data-loopallplayer loop play, values: ‘all’, ‘one’, ‘none’
    data-orderlistplayer play order, values: ‘list’, ‘random’
    data-preloadautovalues: ‘none’, ‘metadata’, ‘auto’
    data-volume0.7default volume, notice that player will remember user setting, default volume will not work after user set volume themselves
    data-mutextrueprevent to play multiple player at the same time, pause other players when this player start play
    data-lrctype0lyric type
    data-listfoldedfalseindicate whether list should folded at first
    data-listmaxheight340pxlist max height
    data-storagenamemetingjslocalStorage key that store player setting

    require代表着这些参数是必须要使用的,其它的参数则可以根据自己需要配置。
    配置全局吸底,data-fixeddata-mini也必须配置,配置为true
    如果使用Pjax,则在class里需添加no-destroy,这样防止切换页面时Aplayer被销毁。

    将以下代码插入到主题配置文件(_config.butterfly.yml)的 “inject.bottom” 中
    1
    2
    3
    4
    inject:
    head:
    bottom:
    - <div class="aplayer no-destroy" data-id="7427714271" data-server="netease" data-type="playlist" data-fixed="true" data-mini="true" data-listFolded="false" data-order="random" data-lrctype="1" data-preload="none" data-autoplay="true" muted></div>
    运行Hexo就可以看到网页左下角出现了Aplayer。最后,如果你想切换页面时,音乐不会中断。请把主题配置文件的 “pjax” 设为 “true” 。
    1
    2
    3
    pjax:
    enable: true
    exclude:
  5. UI 调整

    • 向上调整
      1
      2
      3
      #toggle-sidebar {
      bottom: 80px
      }
      修改主题配置文件`_config.butterfly.yml`,将代码添加到 “inject.head” 中。
      1
      2
      3
      inject:
      head:
      - '<style type="text/css">#toggle-sidebar {bottom: 80px}</style>'
    • 向右调整
      1
      2
      3
      #toggle-sidebar {
      left: 100px
      }
      修改主题配置文件(_config.butterfly.yml),将代码添加到 “inject.head” 中。
      1
      2
      3
      inject:
      head:
      - '<style type="text/css">#toggle-sidebar {left:100px}</style>'

添加贡献日历

效果预览
查看步骤

我的版本可能比较旧,贡献日历已经更新迭代了,所以直接参此教程:Gitcalendar

主页冒泡特效

效果预览
查看步骤

BlogRoot/themes/butterfly/source/js目录下创建一个chocolate.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
/*
* @Author: tzy1997
* @Date: 2020-12-15 20:55:25
* @LastEditors: tzy1997
* @LastEditTime: 2021-01-12 19:02:25
*/

$(function() {
// 气泡
function bubble() {
$('#page-header').circleMagic({
radius: 10,
density: .2,
color: 'rgba(255,255,255,.4)',
clearOffset: 0.99
});
}! function(p) {
p.fn.circleMagic = function(t) {
var o, a, n, r, e = !0,
i = [],
d = p.extend({ color: "rgba(255,0,0,.5)", radius: 10, density: .3, clearOffset: .2 }, t),
l = this[0];

function c() { e = !(document.body.scrollTop > a) }

function s() { o = l.clientWidth, a = l.clientHeight, l.height = a "px", n.width = o, n.height = a }

function h() {
if (e)
for (var t in r.clearRect(0, 0, o, a), i) i[t].draw();
requestAnimationFrame(h)
}

function f() {
var t = this;

function e() { t.pos.x = Math.random() * o, t.pos.y = a 100 * Math.random(), t.alpha = .1 Math.random() * d.clearOffset, t.scale = .1 .3 * Math.random(), t.speed = Math.random(), "random" === d.color ? t.color = "rgba(" Math.floor(255 * Math.random()) ", " Math.floor(0 * Math.random()) ", " Math.floor(0 * Math.random()) ", " Math.random().toPrecision(2) ")" : t.color = d.color }
t.pos = {}, e(), this.draw = function() { t.alpha <= 0 && e(), t.pos.y -= t.speed, t.alpha -= 5e-4, r.beginPath(), r.arc(t.pos.x, t.pos.y, t.scale * d.radius, 0, 2 * Math.PI, !1), r.fillStyle = t.color, r.fill(), r.closePath() }
}! function() {
o = l.offsetWidth, a = l.offsetHeight,
function() {
var t = document.createElement("canvas");
t.id = "canvas", t.style.top = 0, t.style.zIndex = 0, t.style.position = "absolute", l.appendChild(t), t.parentElement.style.overflow = "hidden"
}(), (n = document.getElementById("canvas")).width = o, n.height = a, r = n.getContext("2d");
for (var t = 0; t < o * d.density; t++) {
var e = new f;
i.push(e)
}
h()
}(), window.addEventListener("scroll", c, !1), window.addEventListener("resize", s, !1)
}
}(jQuery);

// 调用气泡方法
bubble();
})

最后,在主题配置文件_config.butterfly.yml中,引入jquery.min.jschocolate.js

1
2
3
4
5
6
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
bottom:
- <script defer src="https://npm.elemecdn.com/jquery@latest/dist/jquery.min.js"></script>
- <script data-pjax defer src="https://npm.elemecdn.com/tzy-blog/lib/js/theme/chocolate.js"></script>

鼠标样式

效果预览
查看步骤

将以下代码复制到custom.css即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
body {
cursor: url(https://bu.dusays.com/2022/05/17/6283c365d20dd.png), auto;
}

.hide-block>.hide-button.open,
.hide-inline>.hide-button.open {
display: block
}

a,
button,
img {
cursor: url(https://bu.dusays.com/2022/05/17/6283c376afcfc.png), auto
}

鼠标 * 字跟随掉落效果

效果预览
查看步骤

BlogRoot/themes/butterfly/source/js目录下创建一个cursor.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
/*!
* Fairy Dust Cursor.js
* - 90's cursors collection
* -- https://github.com/tholman/90s-cursor-effects
* -- http://codepen.io/tholman/full/jWmZxZ/
*/

(function fairyDustCursor() {

var possibleColors = ["#D61C59", "#E7D84B", "#1B8798"]
var width = window.innerWidth;
var height = window.innerHeight;
var cursor = { x: width / 2, y: width / 2 };
var particles = [];

function init() {
bindEvents();
loop();
}

// Bind events that are needed
function bindEvents() {
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchstart', onTouchMove);

window.addEventListener('resize', onWindowResize);
}

function onWindowResize(e) {
width = window.innerWidth;
height = window.innerHeight;
}

function onTouchMove(e) {
if (e.touches.length > 0) {
for (var i = 0; i < e.touches.length; i++) {
addParticle(e.touches[i].clientX, e.touches[i].clientY, possibleColors[Math.floor(Math.random() * possibleColors.length)]);
}
}
}

function onMouseMove(e) {
cursor.x = e.clientX;
cursor.y = e.clientY;

addParticle(cursor.x, cursor.y, possibleColors[Math.floor(Math.random() * possibleColors.length)]);
}

function addParticle(x, y, color) {
var particle = new Particle();
particle.init(x, y, color);
particles.push(particle);
}

function updateParticles() {

// Updated
for (var i = 0; i < particles.length; i++) {
particles[i].update();
}

// Remove dead particles
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i].lifeSpan < 0) {
particles[i].die();
particles.splice(i, 1);
}
}

}

function loop() {
requestAnimationFrame(loop);
updateParticles();
}

/**
* Particles
*/

function Particle() {

this.character = "*";
this.lifeSpan = 120; //ms
this.initialStyles = {
"position": "fixed",
"top": "0", //必须加
"display": "block",
"pointerEvents": "none",
"z-index": "10000000",
"fontSize": "20px",
"will-change": "transform"
};

// Init, and set properties
this.init = function(x, y, color) {

this.velocity = {
x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
y: 1
};

this.position = { x: x - 10, y: y - 20 };
this.initialStyles.color = color;

this.element = document.createElement('span');
this.element.innerHTML = this.character;
applyProperties(this.element, this.initialStyles);
this.update();

document.body.appendChild(this.element);
};

this.update = function() {
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
this.lifeSpan--;

this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (this.lifeSpan / 120) + ")";
}

this.die = function() {
this.element.parentNode.removeChild(this.element);
}

}

/**
* Utils
*/

// Applies css `properties` to an element.
function applyProperties(target, properties) {
for (var key in properties) {
target.style[key] = properties[key];
}
}
if ($(window).innerWidth() > 576) {
init();
}
})();

然后,在主题配置文件_config.butterfly.yml中,引入cursor.js文件。

滚动条

查看步骤

将以下代码复制到custom.css即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
::-webkit-scrollbar {
width: 8px;
height: 8px
}

::-webkit-scrollbar-track {
border-radius: 2em;
/* background-color: rgba(73, 177, 245, .2); */
}

::-webkit-scrollbar-thumb {
background-color: rgb(255 255 255 / .3);
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.1) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.1) 75%, transparent 75%, transparent);
border-radius: 2em
}

::-webkit-scrollbar-corner {
background-color: transparent
}

手机侧边栏默认不展开

若主题版本大于 v4.0.0,可直接在子目录里添加 hide

1
2
3
4
5
6
7
8
9
10
menu:
Home: / || fas fa-home
Archives: /archives/ || fas fa-archive
Tags: /tags/ || fas fa-tags
Categories: /categories/ || fas fa-folder-open
List||fas fa-list||hide:
Music: /music/ || fas fa-music
Movie: /movies/ || fas fa-video
Link: /link/ || fas fa-link
About: /about/ || fas fa-heart

v3.7.1 版本中直接默认子目录是展开的,如果你想要隐藏,按下面步骤操作即可。

效果预览
查看步骤

BlogRoot/themes/butterfly/source/js文件下新建 js 文件,并命名为 custom.js(命名按照自己喜好去命名,只需在主题配置文件_config.butterfly.yml中引入对应的js文件即可),将以下代码复制到新建的custom.js中。

1
2
3
4
5
6
7
8
9
10
11
/* 手机侧边栏默认不展开 */
var mobile_sidebar_menus = document.getElementById("sidebar-menus");
if (mobile_sidebar_menus) {
var menus_item_child = mobile_sidebar_menus.getElementsByClassName(
"menus_item_child"
);
var menus_expand = mobile_sidebar_menus.getElementsByClassName("expand");
for (var i = 0; i < menus_item_child.length; i++) {
menus_item_child[i].style.display = "none";
}
}

图库

图库页面只是普通的页面,你只需要hexo new page xxxxx 创建你的页面就行。

然后使用标签外挂 galleryGroup,具体用法请查看对应的内容。

1
2
3
4
5
<div class="gallery-group-main">
{% galleryGroup 'ACG' '那些二次元的故事' '/gallery/ACG' https://bu.dusays.com/2022/11/26/638228a86935a.webp %}
{% galleryGroup '岳阳' '2017年5月岳阳' '/gallery/YY' https://bu.dusays.com/2022/11/27/63831b681e9f8.jpg %}
{% galleryGroup 'OH MY GIRL' '关于OH MY GIRL的图片' '/Gallery/ohmygirl' https://i.loli.net/2019/12/25/hOqbQ3BIwa6KWpo.jpg %}
</div>

子页面

子页面也是普通的页面,你只需要hexo new page xxxxx 创建你的页面就行。

然后使用标签外挂 gallery,具体用法请查看对应的内容。

1
2
3
4
5
6
7
8
9
10
{% gallery %}
![](https://i.loli.net/2019/12/25/Fze9jchtnyJXMHN.jpg)
![](https://i.loli.net/2019/12/25/ryLVePaqkYm4TEK.jpg)
![](https://i.loli.net/2019/12/25/gEy5Zc1Ai6VuO4N.jpg)
![](https://i.loli.net/2019/12/25/d6QHbytlSYO4FBG.jpg)
![](https://i.loli.net/2019/12/25/6nepIJ1xTgufatZ.jpg)
![](https://i.loli.net/2019/12/25/E7Jvr4eIPwUNmzq.jpg)
![](https://i.loli.net/2019/12/25/mh19anwBSWIkGlH.jpg)
![](https://i.loli.net/2019/12/25/2tu9JC8ewpBFagv.jpg)
{% endgallery %}

如果你想要使用/photo/ohmygirl这样的链接显示你的图片内容

你可以把创建好的ohmygirl整个文件夹移到photo文件夹里去

Valine评论邮件回复提醒

由于 Valine 的国际版共享域名将于 2022 年 8 月 1 日起不再向中国大陆的最终用户提供服务,国际版共享域名仅服务于海外用户。本站已弃用 Valine ,改为 Twikoo。如果你更喜欢 Valine 的风格,你可以使用它的国区版。

参考教程

Hexo 优化 — Valine 扩展之邮件通知
Valine 添加验证码、博主标签及评论微信、QQ 通知

我的表情数据包

这里放上我的valine表情数据,展示如下图:

下载请点击下面按钮:

改写 menhera 表情样式

去除了dark模式下评论者头像的 border 和 padding(我是默认dark,如果不喜欢,则将css中的第一段去掉)。

因为 valine的默认宽度是 25px , 对于 menhera-chan 表情根本无法看清,所以将它pc端评论后的表情加载设置成300px,设屏宽小于768px的,让它继承继承父元素的100%宽 - 30px ,30px是为了与右侧有一段细微间隔,下图可以看到手机端的时候,表情和盒子最右侧是有一定距离的。

对于浏览选择 menhera-chan 表情时,宽度太小,看不清图片,所以这里调整为设备宽的 21%-22% 。QQ和B站表情保持不变,只对 menhera-chan 表情做出改善。

将以下代码复制到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
/* valine 评论 */

/* 去除了dark模式下头像border和padding */
[data-theme='dark'] .v[data-class=v] .vcards .vcard .vimg {
padding: 0;
border: none;
}

[data-theme='dark'] #post .v[data-class=v] .vcontent img {
display: inline-block;
}

.v[data-class=v] .emoji,
.v[data-class=v] .vemoji {
vertical-align: text-bottom;
}

.v[data-class=v] .vwrap .vemojis {
max-height: 260px !important;
}

.v[data-class=v] .vwrap .vemojis i[title|=menhera] {
width: 22% !important;
margin: 5px 10px;
}

.v[data-class=v] .vwrap .vemojis img[alt|=menhera] {
max-width: 100% !important;
}

.v[data-class=v] .vcontent .emoji[alt|=menhera],
.v[data-class=v] .vcontent .vemoji[alt|=menhera] {
max-width: 300px !important;
/* vertical-align: middle; */
margin: 8px 1px;
display: block !important;
}

@media screen and (max-width: 1200px) {
.v[data-class=v] .vwrap .vemojis i[title|=menhera] {
margin: 5px 8px;
}
}

@media screen and (max-width: 768px) {
.v[data-class=v] .vcontent .emoji[alt|=menhera],
.v[data-class=v] .vcontent .vemoji[alt|=menhera] {
max-width: calc(100% - 30px) !important;
}
}

@media screen and (max-width: 576px) {
.v[data-class=v] .vwrap .vemojis {
max-height: 200px !important;
}
.v[data-class=v] .vwrap .vemojis i[title|=menhera] {
margin: 5px 5px;
}
}

@media screen and (max-width: 400px) {
.v[data-class=v] .vwrap .vemojis i[title|=menhera] {
width: 21% !important;
}
}

效果如下:

添加[博主,小伙伴,访客]标签

  1. 打开BlogRoot/themes/butterfly/layout/includes/third-party/comments/valine.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
    function initValine () {
    const valine = new Valine(Object.assign({
    el: '#vcomment',
    appId: '#{theme.valine.appId}',
    appKey: '#{theme.valine.appKey}',
    placeholder: '#{theme.valine.placeholder}',
    avatar: '#{theme.valine.avatar}',
    meta: '#{theme.valine.guest_info }'.split(','),
    pageSize: '#{theme.valine.pageSize}',
    lang: '#{theme.valine.lang}',
    recordIP: #{theme.valine.recordIP},
    serverURLs: '#{theme.valine.serverURLs}',
    emojiCDN: '#{theme.valine.emojiCDN}',
    emojiMaps: !{emojiMaps},
    enableQQ: #{theme.valine.enableQQ},
    path: window.location.pathname,
    requiredFields: [!{theme.valine.requiredFields ? JSON.stringify(theme.valine.requiredFields).split(',') : ''}],
    master: '#{theme.valine.master}'.split(','),
    friends: '#{theme.valine.friends}'.split(','),
    tagMeta: '#{theme.valine.tagMeta || "博主,小伙伴,访客"}'.split(','),
    metaPlaceholder: !{JSON.stringify(theme.valine.metaPlaceholder || {})},
    visitor: #{theme.valine.visitor}
    }, !{JSON.stringify(theme.valine.option)}))
    }
    如图所示:
  2. 修改主题配置文件_config.butterfly.ymlvaline属性。
    • valine配置项添加 md5加密的博主邮箱,小伙伴邮箱

      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
      # valine
      # https://valine.js.org
      valine:
      appId: # leancloud application app id
      appKey: # leancloud application app key
      pageSize: 10 # comment list page size
      avatar: monsterid # gravatar style https://valine.js.org/#/avatar
      lang: zh-CN # i18n: zh-CN/zh-TW/en/ja
      placeholder: # valine comment input placeholder (like: Please leave your footprints)
      guest_info: nick,mail,link # valine comment header info (nick/mail/link)
      recordIP: false # Record reviewer IP
      serverURLs: # This configuration is suitable for domestic custom domain name users, overseas version will be automatically detected (no need to manually fill in)
      bg: # valine background
      emojiCDN: # emoji CDN
      enableQQ: true # enable the Nickname box to automatically get QQ Nickname and QQ Avatar
      requiredFields: nick,mail # required fields (nick/mail)
      master: # md5加密后的博主邮箱
      - d4e7????????????44a14e9a94 #可添加多个
      friends: # md5加密后的小伙伴邮箱
      - 5c?????????????e268ad3819c #可添加多个
      - 7c?????????????e2????3919c
      tagMeta: '博主,小伙伴,访客' # 标签要显示的文字,默认'博主,小伙伴,访客'
      metaPlaceholder:
      nick: 昵称/QQ号(必填)
      mail: 邮箱(必填)
      link: 网址(https://)

      如图所示:

    • 在主题配置文件_config.butterfly.yml的CDN配置项添加如下内容。将Valine.min.js替换成魔改版本。

1
2
3
4
5
6
    CDN:
# comments
gitalk: https://fastly.jsdelivr.net/npm/gitalk@latest/dist/gitalk.min.js
gitalk_css: https://fastly.jsdelivr.net/npm/gitalk/dist/gitalk.min.css
- valine: https://fastly.jsdelivr.net/npm/valine/dist/Valine.min.js
valine: https://fastly.jsdelivr.net/gh/tzy13755126023/BLOG_SOURCE/valine_f/valine.min.js

valine获取评论失败

如下图:

这里并没有加载和渲染 valine 评论数据 , 但在 LeanCloud 数据存储中 是存在评论数据的。

原因 :LeanCloud 国际版通用域名失效

打开控制台发现https://us.avoscloud.com/1.1/classes/Comment?xxxxx已经请求失败(net::ERR_NAME_NOT_RESOLVED),域名也无法ping通。

解决办法:

将 Valine 指定 自定义服务器URL。在主题配置里的 Valine 的 serverURLs 填入https://xxxxxxxx.api.lncldglobal.com。自定义服务器的URL需要到 LeanCloud后台 查看。打开后台之后进入 Settings - App Keys ,Request domain 里面的xxxxxxxx.api.lncldglobal.com就是你需要指定的服务器URL。xxxxxxxx 就是 AppID的前8位字符。

如下图:

经 postman 测试 ,https://xxxxxxxx.api.lncldglobal.com/1.1/classes/Comment?x=x&xx=xx该接口会正常返回评论数据。

关于valine评论,这里会抽空写一篇详细的教程,敬请期待。

首页分类磁铁

原教程:Categories Magnet

效果预览
插件版教程(推荐👍)
  1. 安装依赖,前往博客根目录,打开cmd命令窗口执行如下命令:
    1
    npm install hexo-butterfly-categories-card --save
  2. 添加配置信息,在站点配置文件_config.yml或者主题配置文件_config.butterfly.yml中添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    categoryBar:
    enable: true # 开关
    priority: 5 #过滤器优先权
    enable_page: / # 应用页面
    layout: # 挂载容器类型
    type: id
    name: recent-posts
    index: 0
    column: odd # odd:3列 | even:4列
    row: 1 #显示行数,默认两行,超过行数切换为滚动显示
    message:
    - descr: Ubuntu指南
    cover: https://assets.akilar.top/image/cover1.webp
    - descr: 玩转Win10
    cover: https://assets.akilar.top/image/cover2.webp
    - descr: 长篇小说连载
    cover: https://assets.akilar.top/image/cover3.webp
    - descr: 个人日记
    cover: https://assets.akilar.top/image/cover4.webp
    - descr: 诗词歌赋
    cover: https://assets.akilar.top/image/cover5.webp
    - descr: 杂谈教程
    cover: https://assets.akilar.top/image/cover6.webp
    custom_css: https://npm.elemecdn.com/hexo-butterfly-categories-card@1.0.0/lib/categorybar.css
  3. 参数意义
    参数备选值/类型释义
    prioritynumber【可选】过滤器优先级,数值越小,执行越早,默认为10,选填
    enabletrue/false【必选】控制开关
    enable_pagepath/all【可选】填写想要应用的页面的相对路径(即路由地址),如根目录就填’/‘,分类页面就填’/categories/‘。若要应用于所有页面,就填’all’,默认为’/‘
    layout.typeid/class【可选】挂载容器类型,填写id或class,不填则默认为id
    layout.nametext【必选】挂载容器名称
    layout.index0和正整数【可选】前提是layout.type为class,因为同一页面可能有多个class,此项用来确认究竟排在第几个顺位
    columnodd/even【可选】显示列数,考虑到比例问题,只提供3列和4列,odd为3列, even为4列
    rownumber【可选】显示行数,默认两行,超过行数切换为滚动显示

| message.descr | text | 分类描述,需要和你自己的文章分类一一对应。 |
| message.cover | url | 分类背景,需要和你自己的文章分类一一对应。 |
| custom_css | url | 【可选】自定义样式,会替换默认的css链接,可以下载文档给出的cdn链接后自主修改 |

旧版教程(不推荐)
  1. 修改BlogRoot/themes/butterfly/layout/index.pug
    1
    2
    3
    4
    5
    6
    7
    8
    9
    extends includes/layout.pug
    block content
    include ./includes/mixins/post-ui.pug
    #recent-posts.recent-posts
    if theme.categoryBar.enable
    .recent-post-item(style='height:auto;width:100%;padding:0px;')
    #categoryBar!= list_categories(site.categories,{class: 'categoryBar',depth: 1})
    +postUI
    include includes/pagination.pug
  2. 新建BlogRoot/themes/butterfly/source/css/_layout/categoryBar.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
    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
    if hexo-config('categoryBar.enable')
    #categoryBar
    width 100%!important
    ul
    &.categoryBar-list
    margin 5px 5px 0 5px!important
    padding 0!important

    li
    &.categoryBar-list-item
    font-weight bold
    display inline-block
    height 180px!important
    margin 5px .5% 0 .5%!important
    background-image linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(16, 16, 16, 0) 100%)
    border-radius 10px
    padding 25px 0 25px 25px!important
    box-shadow rgba(50, 50, 50, 0.3) 50px 50px 50px 50px inset
    overflow hidden
    background-size 100%!important
    background-position center!important
    &:hover
    background-size 110%!important
    box-shadow inset 500px 50px 50px 50px rgba(50,50,50, 0.6)
    span
    &.categoryBar-list-count
    &::after
    transition all .5s
    transform translate(-100%, 0)
    a
    &.categoryBar-list-link
    color white!important
    font-size 20px!important
    &::before
    content '|'!important
    color white!important
    font-size 20px!important
    &:after
    content ''
    position relative
    width 0
    bottom 0
    display block
    height 3px
    border-radius 3px
    background-color white
    &:hover
    &:after
    width 90%
    left 1%
    transition all 0.5s

    span
    &.categoryBar-list-count
    display block!important
    color white!important
    font-size 20px!important
    &::before
    content '\f02d'!important
    padding-right 15px!important
    @extend .fontawesomeIcon
    &::after
    padding 5px
    display block!important
    color white!important
    font-size 20px!important
    position relative
    right -100%
    covers = hexo-config('categoryBar.cover')
    for cover,i in covers
    li.categoryBar-list-item:nth-child({i+1})
    background unquote(cover)
    descrs = hexo-config('categoryBar.descr')
    for descr,i in descrs
    li.categoryBar-list-item:nth-child({i+1})>span::after
    content descr!important
    if hexo-config('categoryBar.column') == 'odd'
    li
    &.categoryBar-list-item
    width 32.3%!important
    else if hexo-config('categoryBar.column') == 'even'
    li
    &.categoryBar-list-item
    width 24%!important
    @media screen and (max-width: 650px)
    li
    &.categoryBar-list-item
    width 48%!important
    height 150px!important
    margin 5px 1% 0 1%!important

    $caterow = hexo-config('categoryBar.row')?hexo-config('categoryBar.row'):2
    .categoryBar-list
    max-height 190px * $caterow
    overflow auto
    &::-webkit-scrollbar
    width 0!important
    @media screen and (max-width: 650px)
    .categoryBar-list
    max-height 160px * $caterow
  3. 在主题配置文件_config.butterfly.yml中添加配置项:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    categoryBar:
    enable: true
    column: odd # 显示列数,odd:3列 | even:4列
    row: 2 #显示行数,默认两行,超过行数切换为滚动显示
    descr:
    - Good things to share
    - Back end talk
    - personal diary
    - Front end serialization
    - Butterfly theme
    - Other items
    cover:
    - url('https://fastly.jsdelivr.net/npm/akilar-candyassets/image/cover1.webp')
    - '#abcdef' # HEX格式色值需要用''包裹,不然会被识别成注释
    - rgba(45,67,89,0.7)
    - linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(200,16 , 16, 0) 100%)
    - url('https://fastly.jsdelivr.net/npm/akilar-candyassets/image/cover5.webp')
    - url('https://fastly.jsdelivr.net/npm/akilar-candyassets/image/cover6.webp')

侧边栏电子时钟

效果预览
查看步骤 (新版,推荐👍)

✨可参考教程✨:给butterfly添加侧边栏电子钟

  1. 如果跑过下面旧版的教程,前往博客根目录,卸载原版电子钟插件,打开cmd命令窗口执行如下命令:
    1
    npm uninstall hexo-butterfly-clock
  2. 安装新的插件,前往博客根目录,打开cmd命令窗口执行如下命令:
    1
    npm install hexo-butterfly-clock-anzhiyu --save
  3. 在站点配置文件_config.yml 或 主题配置文件_config.butterfly.yml 中添加配置信息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    electric_clock:
    enable: true # 开关
    priority: 5 #过滤器优先权
    enable_page: all # 应用页面
    exclude:
    # - /posts/
    # - /about/
    layout: # 挂载容器类型
    type: class
    name: sticky_layout
    index: 0
    loading: https://cdn.cbd.int/hexo-butterfly-clock-anzhiyu/lib/loading.gif #加载动画自定义
    clock_css: https://cdn.cbd.int/hexo-butterfly-clock-anzhiyu/lib/clock.min.css
    clock_js: https://cdn.cbd.int/hexo-butterfly-clock-anzhiyu/lib/clock.min.js
    ip_api: https://widget.qweather.net/simple/static/js/he-simple-common.js?v=2.0
    # 和风天气key 默认是 b16a1fa0e63c46a4b8f28abfb06ae3fe
    qweather_key: # 你的key
    # 高得地图web服务key 默认为 e2b04289e870b005374ee030148d64fd&s=rsv3
    gaud_map_key: # 你的key
    default_rectangle: false # 开启后将一直显示rectangle位置的天气,否则将获取访问者的地理位置与天气
    rectangle: 112.982279,28.19409 # 获取访问者位置失败时会显示该位置的天气,同时该位置为开启default_rectangle后的位置
  4. 具体参数含义
    点击查看具体参数
    参数备选值/类型释义
    prioritynumber【可选】过滤器优先级,数值越小,执行越早,默认为 10,选填
    enabletrue/false【必选】控制开关
    enable_pagepath/all【可选】填写想要应用的页面的相对路径(即路由地址),如根目录就填’/‘,分类页面就填’/categories/‘。若要应用于所有页面,就填’all’,默认为 all
    excludepath【可选】填写想要屏蔽的页面,可以多个。写法见示例。原理是将屏蔽项的内容逐个放到当前路径去匹配,若当前路径包含任一屏蔽项,则不会挂载。
    layout.typeid/class【可选】挂载容器类型,填写 id 或 class,不填则默认为 id
    layout.nametext【必选】挂载容器名称
    layout.index0 和正整数【可选】前提是 layout.type 为 class,因为同一页面可能有多个 class,此项用来确认究竟排在第几个顺位
    loadingURL【可选】电子钟加载动画的图片
    clock_cssURL【可选】电子钟样式 CDN 资源
    clock_jsURL【可选】电子钟执行脚本 CDN 资源
    ip_apiURL【可选】获取时钟 IP 的 API
    qweather_keytext【可选】和风天气 key
    gaud_map_keytext【可选】高得地图 web 服务 key
    default_rectangletext【可选】开启后将一直显示 rectangle 位置的天气,否则将获取访问者的地理位置与天气
    rectangletext【可选】获取访问者位置失败时会显示该位置的天气,同时该位置为开启 default_rectangle 后的位置

【qweather_key】和【gaud_map_key】建议自己申请。

qweather_key 申请流程
  1. qweather_key 传送门
  2. 登录后进入控制台(可能要绑定邮箱和手机)
  3. 创建项目,项目名称(名字随意)、勾选【免费订阅】、适用平台【 Web API】、KEY的名称(随意填),最后点击【创建】
  4. 可在项目管理中,到对应的【key】
gaud_map_key 申请流程
  1. gaud_map_key 传送门
  2. 登录后完成一些认证(个人开发),进入控制台
  3. 创建应用,应用名称随意,类型选其他
  4. 点击【添加】,【key名称】随便填,【服务平台】选择 Web服务,点击提交,就得到【key】了
查看步骤(旧版,不建议)

✨参考教程✨: Sidebar Card Clock

  1. 安装依赖,前往博客根目录,打开cmd命令窗口执行如下命令:
    1
    npm install hexo-butterfly-clock --save 
  2. 在站点配置文件_config.yml添加配置项:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # electric_clock
    electric_clock:
    enable: true # 开关
    priority: 5 #过滤器优先权
    enable_page: all # 应用页面
    exclude:
    # - /posts/
    # - /about/
    layout: # 挂载容器类型
    type: class
    name: sticky_layout
    index: 0
    loading: https://fastly.jsdelivr.net/gh/tzy13755126023/BLOG_SOURCE/theme_f/loading.gif #加载动画自定义

更换字体

查看步骤

添加下面这段css即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
@font-face {
font-family: 'tzy';
/* 字体名自定义即可 */
/* src: url('https://cdn.jsdelivr.net/gh/tzy13755126023/BLOG_SOURCE/font/ZhuZiAWan.woff2'); */
src: url('https://npm.elemecdn.com/ethan4116-blog/lib/font/ZhuZiAWan.ttf');
/* 字体文件路径 */
font-display: swap;
}

body,
.gitcalendar {
font-family: tzy !important;
}

局部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

.categoryBar-list {
max-height: 400px;
}

.clock-row {
overflow: hidden;
text-overflow: ellipsis;
}

/*3s为加载动画的时间,1为加载动画的次数,ease-in-out为动画效果*/

#page-header,
#web_bg {
-webkit-animation: imgblur 2s 1 ease-in-out;
animation: imgblur 2s 1 ease-in-out;
}

@keyframes imgblur {
0% {
filter: blur(5px);
}
100% {
filter: blur(0px);
}
}

/*适配使用-webkit内核的浏览器 */

@-webkit-keyframes imgblur {
0% {
-webkit-filter: blur(5px);
}
100% {
-webkit-filter: blur(0px);
}
}
.table-wrap img {
margin: .6rem auto .1rem !important;
}

/* 标签外挂 网站卡片 start */

.site-card-group img {
margin: 0 auto .1rem !important;
}

.site-card-group .info a img {
margin-right: 10px !important;
}

[data-theme='dark'] .site-card-group .site-card .info .title {
color: #f0f0f0 !important;
}

[data-theme='dark'] .site-card-group .site-card .info .desc {
color: rgba(255, 255, 255, .7) !important;
}

.site-card-group .info .desc {
margin-top: 4px !important;
}
/* 代码块颜色 */

figure.highlight pre .addition {
color: #00bf03 !important;
}

禁止右键及F12等事件

效果预览
查看步骤 (新版,推荐👍)

旧版教程(已弃用),对于高版本浏览器,可以先打开控制台再进入站点(亲测 Google Chrome v100),因此本站已弃用forbidden_control(),可直接删除。引入的 function.min.css 也可以删除。

下面开始新的教程,如果你不需要 禁用控制台 以及 禁用一些特殊 keyCode 事件 ,可直接忽略。

  1. 修改【BlogRoot/themes/butterfly/layout/includes/layout.pug】,根据图中位置添加以下 pug 代码(跟 headbody同级)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    script.
    ((function() {var callbacks = [],timeLimit = 50,open = false;setInterval(loop, 1);return {addListener: function(fn) {callbacks.push(fn);},cancleListenr: function(fn) {callbacks = callbacks.filter(function(v) {return v !== fn;});}}
    function loop() {var startTime = new Date();debugger;if (new Date() - startTime > timeLimit) {if (!open) {callbacks.forEach(function(fn) {fn.call(null);});}open = true;window.stop();alert('你真坏,请关闭控制台!');document.body.innerHTML = "";} else {open = false;}}})()).addListener(function() {window.location.reload();});
    script.
    function toDevtools(){
    let num = 0;
    let devtools = new Date();
    devtools.toString = function() {
    num++;
    if (num > 1) {
    alert('你真坏,请关闭控制台!')
    window.location.href = "about:blank"
    blast();
    }
    }
    console.log('', devtools);
    }
    toDevtools();
  2. 将以下代码复制到自定义的custom.js
    1
    2
    3
    document.onkeydown = function (e) {
    if (123 == e.keyCode || (e.ctrlKey && e.shiftKey && (74 === e.keyCode || 73 === e.keyCode || 67 === e.keyCode)) || (e.ctrlKey && 85 === e.keyCode)) return btf.snackbarShow("你真坏,不能打开控制台喔!"), event.keyCode = 0, event.returnValue = !1, !1
    };
  3. 重新编译运行,即可看到效果。
  4. 注意: 如果自己调试阶段,可注释第一步和第二步中的代码,再进行编译,就可以打开控制台了。部署时放开注释,编译好再丢上去就OK了。
查看步骤 (旧版,已弃用)
  1. 在 主题配置 的 inject 的 head 里 引入 这个 css。

    1
    <link rel="stylesheet" href="https://fastly.jsdelivr.net/gh/tzy13755126023/BLOG_SOURCE/css/function.min.css">
  2. 将以下代码复制到自定义的custom.js, 执行 forbidden_control() 执行即可看到效果。

    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
    function forbidden_control() {
    $.extend({
    message: function(a) {
    var b = {
    title: "",
    message: "操作成功",
    time: "3000",
    type: "success",
    showClose: !0,
    autoClose: !0,
    onClose: function() {}
    };
    "string" == typeof a && (b.message = a), "object" == typeof a && (b = $.extend({}, b, a));
    var c, d, e, f = b.showClose ? '<div class="c-message--close">×</div>' : "",
    g = "" !== b.title ? '<h2 class="c-message__title">' b.title "</h2>" : "",
    h = '<div class="c-message animated animated-lento slideInRight"><i class=" c-message--icon c-message--' b.type '"></i><div class="el-notification__group">' g '<div class="el-notification__content">' b.message "</div>" f "</div></div>",
    i = $("body"),
    j = $(h);
    d = function() {
    j.addClass("slideOutRight"), j.one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend", function() {
    e()
    })
    }, e = function() {
    j.remove(), b.onClose(b), clearTimeout(c)
    }, $(".c-message").remove(), i.append(j), j.one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend", function() {
    j.removeClass("messageFadeInDown")
    }), i.on("click", ".c-message--close", function(a) {
    d()
    }), b.autoClose && (c = setTimeout(function() {
    d()
    }, b.time))
    }
    }),
    document.onkeydown = function(e) {
    if (123 == e.keyCode || e.ctrlKey && e.shiftKey && (74 === e.keyCode || 73 === e.keyCode || 67 === e.keyCode) || (e.ctrlKey && 85 === e.keyCode)) return $.message({
    message: "采用本站js及css请注明来源,禁止商业使用!",
    title: "你真坏,不能打开控制台喔!",
    type: "error",
    autoHide: !1,
    time: "3000"
    }), event.keyCode = 0, event.returnValue = !1, !1
    }, document.oncontextmenu = function() {
    return $.message({
    message: "采用本站js及css请注明来源,禁止商业使用!",
    title: "不能右键/长按喔!",
    type: "error",
    autoHide: !1,
    time: "3000"
    }), !1
    }
    }

部分动效说明

查看步骤

请移步此博文 : 特效标签 wow.js

部分页面插入视频

效果预览

实际视频效果请移步: 留言板友链

查看步骤
  1. 替换文件或修改文件。
    如果你所使用的主题版本是 3.7.1 ,可直接下载文件,将BlogRoot/node_modules/hexo-theme-butterfly/source/css/_layout/head.styl替换成新下载的head.styl,将BlogRoot/node_modules/hexo-theme-butterfly/layout/includes/header/index.pug替换成新下载的index.pug
    如果你所使用的主题版本跟本站(v3.7.1)有所出入,请对比一下两个文件(下载的文件和你的主题文件)之间的差异,可能需要你对BlogRoot/themes/butterfly/source/css/_layout/head.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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    &.not-home-page
    height: 20rem

    +maxWidth768()
    height: 14rem !important

    #page-site-info
    position: absolute
    top: 10rem
    padding: 0 .5rem
    width: 100%
    z-index: 2

    +maxWidth768()
    top: 7rem !important

    #post-info
    position: absolute
    ... ...

    &.has-video
    position: relative
    height: 80vh !important

    #page-site-info
    top: 50% !important
    margin-top: -1.425em

    +maxWidth768()
    top: 7rem !important
    margin-top: 0

    +maxWidth768()
    height: 14rem !important

    &.not-top-img
    margin-bottom: .5rem
    ... ...
    主要针对not-home-page#page-site-info修改一些属性,并新增了一个名为has-video的类。
  2. 在自定义 css 中加入以下样式。也可以直接将这段换成style格式写进 head.styl
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #index-video {
    z-index: 0;
    position: absolute;
    top: 0;
    left: 0;
    height: 80vh;
    width: 100%;
    object-fit: cover;
    }
    @media only screen and (max-width: 768px) {
    #index-video {
    display: none;
    }
    }

    @media only screen and (min-width: 768px) {
    .bg-cover {
    background-image: none !important;
    }
    }
  3. 在想插入视频的页面,一定要有某个属性 ,可自行配置 ,如果用 type , 则BlogRoot/themes/butterfly/layout/includes/header/index.pug中则根据对应的 type 类型去写逻辑即可。
    比如我的 BlogRoot/source/comment/index.md 配置如下:
    1
    2
    3
    4
    ---
    title: 留言板
    type: 'comment'
    ---
    所以在BlogRoot/themes/butterfly/layout/includes/header/index.pug中的第 23 行加入 page.type == 'comment'
    1
    - var isHomeClass = is_home() ? 'full_page' : (page.type == 'comment' || page.type == 'link' ) ? 'not-home-page has-video bg-cover' : 'not-home-page'
    第 51 - 56 行 加入
    1
    2
    3
    4
    5
    6
    if page.type == 'comment' 
    video#index-video(autoplay='' loop='' muted='')
    source(src='你的视频地址')
    if page.type == 'link'
    video#index-video(autoplay='' loop='' muted='')
    source(src='你的视频地址')
  4. 如果已经用了主页冒泡特效,请将下面这段代码替换之前的chocolate.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
    /*
    * @Author: tzy1997
    * @Date: 2020-12-15 20:55:25
    * @LastEditors: tzy1997
    * @LastEditTime: 2021-11-25 18:15:47
    */
    // TODO 获取窗口高度 11-19
    var b_h = $(window).height()
    var b_w = $(window).width()

    $(function() {

    // 气泡
    function bubble() {
    $('#page-header').circleMagic({
    radius: 10,
    density: .2,
    color: 'rgba(255,255,255,.4)',
    clearOffset: 0.99
    });
    }! function(p) {
    p.fn.circleMagic = function(t) {
    var o, a, n, r, e = !0,
    i = [],
    d = p.extend({ color: "rgba(255,0,0,.5)", radius: 10, density: .3, clearOffset: .2 }, t),
    l = this[0];

    function c() { e = !(document.body.scrollTop > a) }

    function s() {
    // TODO 获取窗口高度 ethan_tzy
    var a_c = l.clientHeight
    if ($('#index-video').length > 0 && b_w > 768) {
    a = b_h * 0.8
    } else {
    a = a_c
    }
    // o = l.clientWidth, a = l.clientHeight, l.height = a "px", n.width = o, n.height = a
    o = l.clientWidth, l.height = a "px", n.width = o, n.height = a
    }

    function h() {
    if (e)
    for (var t in r.clearRect(0, 0, o, a), i) i[t].draw();
    requestAnimationFrame(h)
    }

    function f() {
    var t = this;

    function e() { t.pos.x = Math.random() * o, t.pos.y = a 100 * Math.random(), t.alpha = .1 Math.random() * d.clearOffset, t.scale = .1 .3 * Math.random(), t.speed = Math.random(), "random" === d.color ? t.color = "rgba(" Math.floor(255 * Math.random()) ", " Math.floor(0 * Math.random()) ", " Math.floor(0 * Math.random()) ", " Math.random().toPrecision(2) ")" : t.color = d.color }
    t.pos = {}, e(), this.draw = function() { t.alpha <= 0 && e(), t.pos.y -= t.speed, t.alpha -= 5e-4, r.beginPath(), r.arc(t.pos.x, t.pos.y, t.scale * d.radius, 0, 2 * Math.PI, !1), r.fillStyle = t.color, r.fill(), r.closePath() }
    }! function() {
    // TODO 气泡的高度 11-19
    var a_c = l.clientHeight
    if ($('#index-video').length > 0 && b_w > 768) {
    a = b_h * 0.8
    } else {
    a = a_c
    }
    o = l.offsetWidth,
    // o = l.offsetWidth, a = l.offsetHeight,
    function() {
    var t = document.createElement("canvas");
    t.id = "canvas", t.style.top = 0, t.style.zIndex = 0, t.style.position = "absolute", l.appendChild(t), t.parentElement.style.overflow = "hidden"
    }(), (n = document.getElementById("canvas")).width = o, n.height = a, r = n.getContext("2d");
    for (var t = 0; t < o * d.density; t++) {
    var e = new f;
    i.push(e)
    }
    h()
    }(), window.addEventListener("scroll", c, !1), window.addEventListener("resize", s, !1)
    }
    }(jQuery);
    bubble();
    })
  5. 重新编译运行,即可看到效果。

公告栏两个小人

效果预览
查看步骤

在【BlogRoot/themes/butterfly/layout/includes/widget/card_announcement.pug】下添加如下部分代码。

注意: 将代码复制到【card_announcement.pug】文件以后,不难发现会有重复的一段代码。你要做的一步操作是,删除重复的代码(优先保留你主题版本原有的代码), 这里之所以没用 Diff 代码块,是因为怕删除【+】号的时候在格式上特别容易出错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if theme.aside.card_announcement.enable
.card-widget.card-announcement
.item-headline
i.fas.fa-bullhorn.card-announcement-animation
span= _p('aside.card_announcement')
.announcement_content!= theme.aside.card_announcement.content
.xpand(style='height:200px;')
canvas.illo(width='800' height='800' style='max-width: 200px; max-height: 200px; touch-action: none; width: 640px; height: 640px;')
script(src='https://npm.elemecdn.com/ethan4116-blog/lib/js/other/two-people/twopeople1.js')
script(src='https://npm.elemecdn.com/ethan4116-blog/lib/js/other/two-people/zdog.dist.js')
script#rendered-js(src='https://npm.elemecdn.com/ethan4116-blog/lib/js/other/two-people/twopeople.js')
style.
.card-widget.card-announcement {
margin: 0;
align-items: center;
justify-content: center;
text-align: center;
}
canvas {
display: block;
margin: 0 auto;
cursor: move;
}

星空背景和流星特效

查看步骤
  1. BlogRoot/themes/butterfly/source/js目录下新建universe.js,输入以下代码:
    1
    2
    function dark() {window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;var n,e,i,h,t=.05,s=document.getElementById("universe"),o=!0,a="180,184,240",r="226,225,142",d="226,225,224",c=[];function f(){n=window.innerWidth,e=window.innerHeight,i=.216*n,s.setAttribute("width",n),s.setAttribute("height",e)}function u(){h.clearRect(0,0,n,e);for(var t=c.length,i=0;i<t;i++){var s=c[i];s.move(),s.fadeIn(),s.fadeOut(),s.draw()}}function y(){this.reset=function(){this.giant=m(3),this.comet=!this.giant&&!o&&m(10),this.x=l(0,n-10),this.y=l(0,e),this.r=l(1.1,2.6),this.dx=l(t,6*t)+(this.comet+1-1)*t*l(50,120)+2*t,this.dy=-l(t,6*t)-(this.comet+1-1)*t*l(50,120),this.fadingOut=null,this.fadingIn=!0,this.opacity=0,this.opacityTresh=l(.2,1-.4*(this.comet+1-1)),this.do=l(5e-4,.002)+.001*(this.comet+1-1)},this.fadeIn=function(){this.fadingIn&&(this.fadingIn=!(this.opacity>this.opacityTresh),this.opacity+=this.do)},this.fadeOut=function(){this.fadingOut&&(this.fadingOut=!(this.opacity<0),this.opacity-=this.do/2,(this.x>n||this.y<0)&&(this.fadingOut=!1,this.reset()))},this.draw=function(){if(h.beginPath(),this.giant)h.fillStyle="rgba("+a+","+this.opacity+")",h.arc(this.x,this.y,2,0,2*Math.PI,!1);else if(this.comet){h.fillStyle="rgba("+d+","+this.opacity+")",h.arc(this.x,this.y,1.5,0,2*Math.PI,!1);for(var t=0;t<30;t++)h.fillStyle="rgba("+d+","+(this.opacity-this.opacity/20*t)+")",h.rect(this.x-this.dx/4*t,this.y-this.dy/4*t-2,2,2),h.fill()}else h.fillStyle="rgba("+r+","+this.opacity+")",h.rect(this.x,this.y,this.r,this.r);h.closePath(),h.fill()},this.move=function(){this.x+=this.dx,this.y+=this.dy,!1===this.fadingOut&&this.reset(),(this.x>n-n/4||this.y<0)&&(this.fadingOut=!0)},setTimeout(function(){o=!1},50)}function m(t){return Math.floor(1e3*Math.random())+1<10*t}function l(t,i){return Math.random()*(i-t)+t}f(),window.addEventListener("resize",f,!1),function(){h=s.getContext("2d");for(var t=0;t<i;t++)c[t]=new y,c[t].reset();u()}(),function t(){document.getElementsByTagName('html')[0].getAttribute('data-theme')=='dark'&&u(),window.requestAnimationFrame(t)}()};
    dark()
  2. BlogRoot/themes/butterfly/source/css目录下新建universe.css,输入以下代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /* 背景宇宙星光  */
    #universe{
    display: block;
    position: fixed;
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: -1;
    }
  3. 在主题配置文件_config.butterfly.ymlinject配置项中bottom下填入:
    1
    2
    3
    4
    5
    inject:
    bottom:
    # 星空背景
    - <canvas id="universe"></canvas>
    - <script defer src="/js/universe.js"></script>
  4. 在主题配置文件_config.butterfly.ymlinject配置项中head下填入:
    1
    2
    3
    4
    inject:
    head:
    ## 星空背景
    - <link rel="stylesheet" href="/css/universe.css">
  5. 重新编译即可看到效果。

樱花飘落效果

效果预览
查看步骤

在主题配置文件_config.butterfly.ymlinject配置项中bottom下引入sakura.js即可。

1
2
3
4
inject:
bottom:
# 樱花飘落效果
# - <script async src="https://npm.elemecdn.com/tzy-blog/lib/js/other/sakura.js"></script>

灯笼特效

外挂标签

添加github徽标

自定义右键菜单

参考方向教程原贴
TZYHexo Butterfly 自定义右键菜单(基础)
ZHHEOButterfly 魔改:自定义右键菜单
LYX博客自定义右键菜单升级版

加载动画

可参考 Loading Animation

评论弹幕

参考教程 Butterfly 主题的留言弹幕界面增强版(支持 Twikoo、Waline、Valine)

自定义页脚

效果预览
查看教程

侧边栏公众号

效果预览
查看教程

文章加密插件

效果预览

点击 Demo Page , 所有的密码都是 【hello】。

查看教程

详见开源地址:hexo-blog-encrypt

  1. 在根目录执行以下命令
    1
    npm install --save hexo-blog-encrypt
  2. Front matter配置方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ---
    title: Hello World
    tags:
    - 作为日记加密
    date: 2016-03-30 21:12:21
    password: mikemessi
    abstract: 有东西被加密了, 请输入密码查看.
    message: 您好, 这里需要密码.
    theme: xray
    wrong_pass_message: 抱歉, 这个密码看着不太对, 请再试试.
    wrong_hash_message: 抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容.
    ---
  3. 可以在线挑选你喜欢的主题,并应用到你的博客中: defaultblinkshrinkflipupsurgewavexray
  4. 重新编译项目并进入对应的文章页即可看到加密效果

友链朋友圈

效果预览

效果请移步:朋友圈

查看教程