【Hexo】美化教程合集 1
AiGuoHou- 鉴于每个人的根目录名称都不一样,本帖博客根目录一律以[BlogRoot]指代。
- 本贴魔改均基于butterfly主题。
- 本帖涉及魔改源码的内容,会使用diff代码块标识,复制时请不要忘记删除前面的+、-符号。
- 因为.pug和.styl以及.yml等对缩进要求较为严格,请尽量不要使用记事本等无法提供语法高亮的文本编辑器进行修改。
- 本帖基于Butterfly主题进行魔改方案编写,因此请读者优先掌握Butterfly主题官方文档的内容后再来进行魔改。
- 魔改会过程常常引入自定义的css与js文件,方法见【Hexo】添加自定义css和js文件
1 直达底部按钮
点击查看教程
在[BlogRoot]\themes\butterfly\layout\includes\rightside.pug做以下修改:
| 1 | button#go-up(type="button" title=_p("rightside.back_to_top")) | 
2 网站恶搞标题
点击查看教程
- 
新建文件 [BlogRoot]\source\js\title.js,写入以下内容:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17//动态标题 
 var OriginTitile = document.title;
 var titleTime;
 document.addEventListener('visibilitychange', function () {
 if (document.hidden) {
 //离开当前页面时标签显示内容
 document.title = '👀跑哪里去了~';
 clearTimeout(titleTime);
 } else {
 //返回当前页面时标签显示内容
 document.title = '🐖抓到你啦~';
 //两秒后变回正常标题
 titleTime = setTimeout(function () {
 document.title = OriginTitile;
 }, 2000);
 }
 });
- 
在主题配置文件 _config.butterfly.yml引入该文件:1 
 2
 3inject: 
 bottom:
 + - <script async src="/js/title.js"></script>
- 
重启项目: 1 hexo cl && hexo s 
3 随机壁纸API汇总
点击查看教程
网上可以查到很多随机壁纸的API,但是很多都用不了或者是图片质量比较低,于是今天汇总了一些目前可以用的随机壁纸API,其中列出来的图片质量都是比较高的,可以放心食用,本站随机壁纸API模块用的都是这部分API。
| 1 | //IMGAPI | 
API链接就是引号引着的部分,具体的参数可以到相应官网查看API文档,这部分已经通过测试,到目前为止都是可用的,并且壁纸质量比较高;尤其是必应、unsplash、picsum这几个API的图片质量十分高,赶紧给你的网站换上随机壁纸吧!
4 语雀同款链接卡片
点击查看教程
- 在 [BlogRoot]\themes\butterfly\scripts\tag文件夹下面新建link.js并粘贴如下代码:
| 1 | /** | 
- 在 [BlogRoot]\themes\butterfly\source\css\_tags文件夹下面新建link.styl并粘贴如下代码:
| 1 | .link_card | 
- 注意:内容不能有英文逗号,不然会出bug
| 1 | <!-- 使用html是为了高亮代码,不必在意 --> | 
| 参数 | 描述 | 默认值 | 
|---|---|---|
| 链接 | 如果连接中包含http则新标签打开,否则本标签页打开 | 无 | 
| 标题 | 网站的标题 | 点击直达链接 | 
| 图标 | 网站favicon 链接 | |
| 介绍 | 网站的description | 无 | 
5 渐变色版权美化
点击查看教程
- 
修改 [BlogRoot]\themes\butterfly\layout\includes\post\post-copyright.pug,直接复制以下内容替换原文件内容。此处多次用到了三元运算符作为默认项设置,在确保有主题配置文件的默认项的情况下,也可以在相应文章的front-matter中重新定义作者,原文链接,开源许可协议等内容。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
 32if theme.post_copyright.enable && page.copyright !== false 
 - let author = page.copyright_author ? page.copyright_author : config.author
 - let url = page.copyright_url ? page.copyright_url : page.permalink
 - let license = page.license ? page.license : theme.post_copyright.license
 - let license_url = page.license_url ? page.license_url : theme.post_copyright.license_url
 .post-copyright
 .post-copyright__title
 span.post-copyright-info
 h #[=page.title]
 .post-copyright__type
 span.post-copyright-info
 a(href=url_for(url))= theme.post_copyright.decode ? decodeURI(url) : url
 .post-copyright-m
 .post-copyright-m-info
 .post-copyright-a
 h 作者
 .post-copyright-cc-info
 h=author
 .post-copyright-c
 h 发布于
 .post-copyright-cc-info
 h=date(page.date, config.date_format)
 .post-copyright-u
 h 更新于
 .post-copyright-cc-info
 h=date(page.updated, config.date_format)
 .post-copyright-c
 h 许可协议
 .post-copyright-cc-info
 a.icon(rel='noopener' target='_blank' title='Creative Commons' href='https://creativecommons.org/')
 i.fab.fa-creative-commons
 a(rel='noopener' target='_blank' title=license href=url_for(license_url))=license
- 
修改 [BlogRoot]\themes\butterfly\source\css\_layout\post.styl,直接复制以下内容,替换原文件,这个文件就是自己调节样式的。其中,184行是白天模式的背景色,这里默认是我网站的渐变色,大家可以根据自己的喜好调节;253行是夜间模式的发光光圈颜色,大家也可以自行替换成自己喜欢的颜色: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
 264beautify() 
 headStyle(fontsize)
 padding-left: unit(fontsize + 12, 'px')
 &:before
 margin-left: unit((-(fontsize + 6)), 'px')
 font-size: unit(fontsize, 'px')
 &:hover
 padding-left: unit(fontsize + 18, 'px')
 h1,
 h2,
 h3,
 h4,
 h5,
 h6
 transition: all .2s ease-out
 &:before
 position: absolute
 top: calc(50% - 7px)
 color: $title-prefix-icon-color
 content: $title-prefix-icon
 line-height: 1
 transition: all .2s ease-out
 @extend .fontawesomeIcon
 &:hover
 &:before
 color: $light-blue
 h1
 headStyle(20)
 h2
 headStyle(18)
 h3
 headStyle(16)
 h4
 headStyle(14)
 h5
 headStyle(12)
 h6
 headStyle(12)
 ol,
 ul
 p
 margin: 0 0 8px
 li
 &::marker
 color: $light-blue
 font-weight: 600
 font-size: 1.05em
 &:hover
 &::marker
 color: var(--pseudo-hover)
 ul > li
 list-style-type: circle
 #article-container
 word-wrap: break-word
 overflow-wrap: break-word
 a
 color: $theme-link-color
 &:hover
 text-decoration: underline
 img
 display: block
 margin: 0 auto 20px
 max-width: 100%
 transition: filter 375ms ease-in .2s
 p
 margin: 0 0 16px
 iframe
 margin: 0 0 20px
 if hexo-config('anchor')
 a.headerlink
 &:after
 @extend .fontawesomeIcon
 float: right
 color: var(--headline-presudo)
 content: '\f0c1'
 font-size: .95em
 opacity: 0
 transition: all .3s
 &:hover
 &:after
 color: var(--pseudo-hover)
 h1,
 h2,
 h3,
 h4,
 h5,
 h6
 &:hover
 a.headerlink
 &:after
 opacity: 1
 ol,
 ul
 ol,
 ul
 padding-left: 20px
 li
 margin: 4px 0
 p
 margin: 0 0 8px
 if hexo-config('beautify.enable')
 if hexo-config('beautify.field') == 'site'
 beautify()
 else if hexo-config('beautify.field') == 'post'
 &.post-content
 beautify()
 > :last-child
 margin-bottom: 0
 #post
 .tag_share
 .post-meta
 &__tag-list
 display: inline-block
 &__tags
 display: inline-block
 margin: 8px 8px 8px 0
 padding: 0 12px
 width: fit-content
 border: 1px solid $light-blue
 border-radius: 12px
 color: $light-blue
 font-size: .85em
 transition: all .2s ease-in-out
 &:hover
 background: $light-blue
 color: var(--white)
 .post_share
 display: inline-block
 float: right
 margin: 8px 0
 width: fit-content
 .social-share
 font-size: .85em
 .social-share-icon
 margin: 0 4px
 width: w = 1.85em
 height: w
 font-size: 1.2em
 line-height: w
 .post-copyright
 position: relative
 margin: 40px 0 10px
 padding: 10px 16px
 border: 1px solid var(--light-grey)
 transition: box-shadow .3s ease-in-out
 overflow: hidden
 border-radius: 12px
 background: linear-gradient(45deg, #f6d8f5, #c2f1f0, #f0debf);
 &:before
 background var(--heo-post-blockquote-bg)
 position absolute
 right -26px
 top -120px
 content '\f25e'
 font-size 200px
 font-family 'Font Awesome 5 Brands'
 opacity .2
 &:hover
 box-shadow: 0 0 8px 0 rgba(232, 237, 250, .6), 0 2px 4px 0 rgba(232, 237, 250, .5)
 .post-copyright
 &-meta
 color: $light-blue
 font-weight: bold
 &-info
 padding-left: 6px
 a
 text-decoration: none
 word-break: break-word
 &:hover
 text-decoration: none
 .post-copyright-cc-info
 color: $theme-color;
 .post-outdate-notice
 position: relative
 margin: 0 0 20px
 padding: .5em 1.2em
 border-radius: 3px
 background-color: $noticeOutdate-bg
 color: $noticeOutdate-color
 if hexo-config('noticeOutdate.style') == 'flat'
 padding: .5em 1em .5em 2.6em
 border-left: 5px solid $noticeOutdate-border
 &:before
 @extend .fontawesomeIcon
 position: absolute
 top: 50%
 left: .9em
 color: $noticeOutdate-border
 content: '\f071'
 transform: translateY(-50%)
 .ads-wrap
 margin: 40px 0
 .post-copyright-m-info
 .post-copyright-a,
 .post-copyright-c,
 .post-copyright-u
 display inline-block
 width fit-content
 padding 2px 5px
 [data-theme="dark"]
 #post
 .post-copyright
 background #07080a
 text-shadow #bfbeb8 0 0 2px
 border 1px solid rgb(19 18 18 / 35%)
 box-shadow 0 0 5px var(--theme-color)
 animation flashlight 1s linear infinite alternate
 .post-copyright-info
 color #e0e0e4
 #post
 .post-copyright__title
 font-size 22px
 .post-copyright__notice
 font-size 15px
 .post-copyright
 box-shadow 2px 2px 5px
- 
默认项的配置 - 
作者: [BlogRoot]\_config.yml中的author配置项1 
 2
 3
 4
 5
 6
 7
 8# Site 
 title: Akilarの糖果屋
 subtitle: Akilar.top
 description:
 keywords:
 author: Akilar #默认作者
 language: zh-CN
 timezone: ''
- 
许可协议: [BlogRoot]\_config.butterfly.yml中的license和license_url配置项1 
 2
 3
 4
 5post_copyright: 
 enable: true
 decode: true
 license: CC BY-NC-SA 4.0
 license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/
 
- 
- 
页面覆写配置项,修改对应文章的 front-matter1 
 2
 3
 4
 5
 6
 7
 8
 9--- 
 title: Copyright-beautify # 文章名称
 date: 2021-03-02 13:52:46 # 文章发布日期
 updated: 2023-11-25 12:27:56 # 文章更新日期
 copyright_author: Nesxc # 作者覆写
 copyright_url: https://www.nesxc.com/post/hexocc.html # 原文链接覆写
 license: # 许可协议名称覆写
 license_url: # 许可协议链接覆写
 ---
6 评论表情包放大
点击查看教程
其实实现的原理很简单,就是创建一个盒子,将表情包的内容放在盒子里面,然后控制盒子位置和显示隐藏即可。
- 
新建文件 [BlogRoot]\source\js\emoji.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// 如果当前页有评论就执行函数 
 if (document.getElementById('post-comment')) owoBig();
 // 表情放大
 function owoBig() {
 let flag = 1, // 设置节流阀
 owo_time = '', // 设置计时器
 m = 3; // 设置放大倍数
 // 创建盒子
 let div = document.createElement('div'),
 body = document.querySelector('body');
 // 设置ID
 div.id = 'owo-big';
 // 插入盒子
 body.appendChild(div)
 // 构造observer
 let observer = new MutationObserver(mutations => {
 for (let i = 0; i < mutations.length; i++) {
 let dom = mutations[i].addedNodes,
 owo_body = '';
 if (dom.length == 2 && dom[1].className == 'OwO-body') owo_body = dom[1];
 // 如果需要在评论内容中启用此功能请解除下面的注释
 // else if (dom.length == 1 && dom[0].className == 'tk-comment') owo_body = dom[0];
 else continue;
 // 禁用右键(手机端长按会出现右键菜单,为了体验给禁用掉)
 if (document.body.clientWidth <= 768) owo_body.addEventListener('contextmenu', e => e.preventDefault());
 // 鼠标移入
 owo_body.onmouseover = (e) => {
 if (flag && e.target.tagName == 'IMG') {
 flag = 0;
 // 移入300毫秒后显示盒子
 owo_time = setTimeout(() => {
 let height = e.path[0].clientHeight * m, // 盒子高
 width = e.path[0].clientWidth * m, // 盒子宽
 left = (e.x - e.offsetX) - (width - e.path[0].clientWidth) / 2, // 盒子与屏幕左边距离
 top = e.y - e.offsetY; // 盒子与屏幕顶部距离
 if ((left + width) > body.clientWidth) left -= ((left + width) - body.clientWidth + 10); // 右边缘检测,防止超出屏幕
 if (left < 0) left = 10; // 左边缘检测,防止超出屏幕
 // 设置盒子样式
 div.style.cssText = `display:flex; height:${height}px; width:${width}px; left:${left}px; top:${top}px;`;
 // 在盒子中插入图片
 div.innerHTML = `<img src="${e.target.src}">`
 }, 300);
 }
 };
 // 鼠标移出隐藏盒子
 owo_body.onmouseout = () => { div.style.display = 'none', flag = 1, clearTimeout(owo_time); }
 }
 })
 observer.observe(document.getElementById('post-comment'), { subtree: true, childList: true }) // 监听的 元素 和 配置项
 }
- 
新建文件 [BlogRoot]\source\css\emoji.css,写入如下内容(更推荐全部写在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#owo-big { 
 position: fixed;
 align-items: center;
 background-color: rgb(255, 255, 255);
 border: 1px #aaa solid;
 border-radius: 10px;
 z-index: 9999;
 display: none;
 transform: translate(0, -105%);
 overflow: hidden;
 animation: owoIn 0.3s cubic-bezier(0.42, 0, 0.3, 1.11);
 }
 [data-theme=dark] #owo-big {
 background-color: #4a4a4a
 }
 #owo-big img {
 width: 100%;
 }
 /* 动画效果代码由 Heo:https://blog.zhheo.com/ 提供 */
 @keyframes owoIn {
 0% {
 transform: translate(0, -95%);
 opacity: 0;
 }
 100% {
 transform: translate(0, -105%);
 opacity: 1;
 }
 }
- 
引入 css和js文件,略
- 
重启项目,略 
7 Vue+Element样式弹窗
点击查看教程
- 
在主题配置文件 [BlogRoot]\_config.butterfly.yml中 引入Vue和Element相关依赖:1 
 2
 3
 4
 5
 6inject: 
 head:
 + - <link rel="stylesheet" href="https://cdn1.tianli0.top/npm/element-ui@2.15.6/packages/theme-chalk/lib/index.css"> # 引入组件库(f12)
 bottom:
 + - <script async src="https://cdn1.tianli0.top/npm/vue@2.6.14/dist/vue.min.js"></script> # 引入VUE(f12)
 + - <script async src="https://cdn1.tianli0.top/npm/element-ui@2.15.6/lib/index.js"></script> # 引入ElementUI(f12)
- 
在你想要弹出弹窗的js代码中加入如下代码即可触发弹窗: 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13new Vue({ 
 data: function () {
 this.$notify({
 title: "你已被发现😜",
 message: "小伙子,扒源记住要遵循GPL协议!",
 position: 'top-left',
 offset: 50,
 showClose: true,
 type: "warning",
 duration: 5000
 });
 }
 })- 
notify:弹窗类型,可以替换为message(信息提示)和confirm(二次确认提示)
- 
title:弹窗标题,可以改为自定义标题
- 
message:弹窗信息,可以改为自定义内容
- 
position:弹出位置,bottom、top和left、right两两组合
- 
offset:偏移量,简单可以理解为与边界的距离
- 
showClose:是否显示关闭按钮
- 
type:提示类型,可选success/warning/info/error等
- 
duration:停留时间,弹出停留至消失的时间,单位ms详见:Vue中常用的提示信息 
 
- 
8 按键防抖
点击查看教程
我们的博客按钮非常多,可能你平时并不在意,如果你为f12按钮绑定了一个弹窗,那当你长按f12可能会无限触发弹窗,这就是没有做按键防抖的后果,我们的是静态博客,所以只消耗本地的资源,如果是有后端服务的,频繁触发某个逻辑可能会消耗服务器资源,因此我们必须在前端过滤这些非法操作,不能让其跑到后端!我这里用的是最初等的计时器对象来防抖,原理就是延迟某个时间再触发逻辑(例如300ms),如果这段时间内按键再次按下直接忽略。
- 
在任意一个js文件引入以下代码(我是在 [BlogRoot]\source\js\custom.js引入的),这个js文件的引入最好在前面,否则可能不能及时生效1 
 2
 3
 4
 5
 6
 7// 防抖全局计时器 
 let TT = null; //time用来控制事件的触发
 // 防抖函数:fn->逻辑 time->防抖时间
 function debounce(fn, time) {
 if (TT !== null) clearTimeout(TT);
 TT = setTimeout(fn, time);
 }
- 
将你需要防抖的函数 fn()用debounce(fn, 300)替代,防抖时间可以自定义,单位为ms,下面就是一个例子1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18// 复制提醒 
 document.addEventListener("copy", function () {
 debounce(function () {
 new Vue({
 data: function () {
 this.$notify({
 title: "哎嘿!复制成功🍬",
 message: "若要转载最好保留原文链接哦,给你一个大大的赞!",
 position: 'top-left',
 offset: 50,
 showClose: true,
 type: "success",
 duration: 5000
 });
 }
 })
 }, 300);
 })
- 
在主题配置文件引入以上js文件,具体过程略。这样写全局都是用一个计时器,考虑到我们的博客较为简单,这样做实测是没啥问题了,再也不怕手抖了! 
9 夜间模式动画(店长)
点击查看教程
详见:夜间模式动画(店长)
- 
新建 [BlogRoot]\themes\butterfly\layout\includes\custom\sun_moon.pug,这部分其实实质上就是一个svg文件,通过js操作它的旋转显隐,淡入淡出实现动画效果。1 
 2
 3
 4
 5
 6
 7
 8
 9svg(aria-hidden='true', style='position:absolute; overflow:hidden; width:0; height:0') 
 symbol#icon-sun(viewBox='0 0 1024 1024')
 path(d='M960 512l-128 128v192h-192l-128 128-128-128H192v-192l-128-128 128-128V192h192l128-128 128 128h192v192z', fill='#FFD878', p-id='8420')
 path(d='M736 512a224 224 0 1 0-448 0 224 224 0 1 0 448 0z', fill='#FFE4A9', p-id='8421')
 path(d='M512 109.248L626.752 224H800v173.248L914.752 512 800 626.752V800h-173.248L512 914.752 397.248 800H224v-173.248L109.248 512 224 397.248V224h173.248L512 109.248M512 64l-128 128H192v192l-128 128 128 128v192h192l128 128 128-128h192v-192l128-128-128-128V192h-192l-128-128z', fill='#4D5152', p-id='8422')
 path(d='M512 320c105.888 0 192 86.112 192 192s-86.112 192-192 192-192-86.112-192-192 86.112-192 192-192m0-32a224 224 0 1 0 0 448 224 224 0 0 0 0-448z', fill='#4D5152', p-id='8423')
 symbol#icon-moon(viewBox='0 0 1024 1024')
 path(d='M611.370667 167.082667a445.013333 445.013333 0 0 1-38.4 161.834666 477.824 477.824 0 0 1-244.736 244.394667 445.141333 445.141333 0 0 1-161.109334 38.058667 85.077333 85.077333 0 0 0-65.066666 135.722666A462.08 462.08 0 1 0 747.093333 102.058667a85.077333 85.077333 0 0 0-135.722666 65.024z', fill='#FFB531', p-id='11345')
 path(d='M329.728 274.133333l35.157333-35.157333a21.333333 21.333333 0 1 0-30.165333-30.165333l-35.157333 35.157333-35.114667-35.157333a21.333333 21.333333 0 0 0-30.165333 30.165333l35.114666 35.157333-35.114666 35.157334a21.333333 21.333333 0 1 0 30.165333 30.165333l35.114667-35.157333 35.157333 35.157333a21.333333 21.333333 0 1 0 30.165333-30.165333z', fill='#030835', p-id='11346')
- 
新建 [BlogRoot]\themes\butterfly\source\css\_layout\sun_moon.styl1 
 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.Cuteen_DarkSky, 
 .Cuteen_DarkSky:before
 content ''
 position fixed
 left 0
 right 0
 top 0
 bottom 0
 z-index 88888888
 .Cuteen_DarkSky
 background linear-gradient(#feb8b0, #fef9db)
 &:before
 transition 2s ease all
 opacity 0
 background linear-gradient(#4c3f6d, #6c62bb, #93b1ed)
 .DarkMode
 .Cuteen_DarkSky
 &:before
 opacity 1
 .Cuteen_DarkPlanet
 z-index 99999999
 position fixed
 left -50%
 top -50%
 width 200%
 height 200%
 -webkit-animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
 animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
 transform-origin center bottom
 @-webkit-keyframes CuteenPlanetMove {
 0% {
 transform: rotate(0);
 }
 to {
 transform: rotate(360deg);
 }
 }
 @keyframes CuteenPlanetMove {
 0% {
 transform: rotate(0);
 }
 to {
 transform: rotate(360deg);
 }
 }
 .Cuteen_DarkPlanet
 &:after
 position absolute
 left 35%
 top 40%
 width 9.375rem
 height 9.375rem
 border-radius 50%
 content ''
 background linear-gradient(#fefefe, #fffbe8)
 .search
 span
 display none
 .menus_item
 a
 text-decoration none
 //按钮相关,对侧栏按钮做过魔改的可以调整这里的数值
 .icon-V
 padding 5px
- 
新建 [BlogRoot]\themes\butterfly\source\js\sun_moon.js,去除了冗余代码,去jquery1 
 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
 28function switchNightMode() { 
 document.querySelector('body').insertAdjacentHTML('beforeend', '<div class="Cuteen_DarkSky"><div class="Cuteen_DarkPlanet"></div></div>'),
 setTimeout(function() {
 document.querySelector('body').classList.contains('DarkMode') ? (document.querySelector('body').classList.remove('DarkMode'), localStorage.setItem('isDark', '0'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')) : (document.querySelector('body').classList.add('DarkMode'), localStorage.setItem('isDark', '1'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')),
 setTimeout(function() {
 document.getElementsByClassName('Cuteen_DarkSky')[0].style.transition = 'opacity 3s';
 document.getElementsByClassName('Cuteen_DarkSky')[0].style.opacity = '0';
 setTimeout(function() {
 document.getElementsByClassName('Cuteen_DarkSky')[0].remove();
 }, 1e3);
 }, 2e3)
 })
 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)
 document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')
 } else {
 activateLightMode()
 saveToLocal.set('theme', 'light', 2)
 document.querySelector('body').classList.add('DarkMode'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')
 }
 // handle some cases
 typeof utterancesTheme === 'function' && utterancesTheme()
 typeof FB === 'object' && window.loadFBComment()
 window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
 }
- 
修改 [BlogRoot]\themes\butterfly\layout\includes\head.pug,在文件末位加上一行1 
 2
 3
 4
 5
 6
 7
 8
 9
 10//- global config 
 !=partial('includes/head/config', {}, {cache: true})
 include ./head/config_site.pug
 include ./head/noscript.pug
 !=fragment_cache('injectHeadJs', function(){return inject_head_js()})
 !=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})
 + include ./custom/sun_moon.pug
- 
修改 [BlogRoot]\themes\butterfly\layout\includes\rightside.pug,把原本的昼夜切换按钮替换掉1 
 2
 3
 4
 5
 6
 7
 8
 9
 10when 'translate' 
 if translate.enable
 button#translateLink(type="button" title=_p('rightside.translate_title'))= translate.default
 when 'darkmode'
 if darkmode.enable && darkmode.button
 - button#darkmode(type="button" title=_p('rightside.night_mode_title'))
 - i.fas.fa-adjust
 + a.icon-V.hidden(onclick='switchNightMode()', title=_p('rightside.night_mode_title'))
 + svg(width='25', height='25', viewBox='0 0 1024 1024')
 + use#modeicon(xlink:href='#icon-moon')
- 
修改 [BlogRoot]\_config.butterfly.yml,引入一下js1 
 2
 3inject: 
 bottom:
 + - <script async src="/js/sun_moon.js"></script>
- 
重启项目并切换夜间模式即可看见效果 1 hexo cl; hexo s 
10 夜间模式切换动画2.0
点击查看教程
逛博客看见别人的切换动画有月亮,而且颜色也很好看,于是一顿f12操作下大概看懂原理,再结合现在的动画改进一下就是了。(注意:在做本魔改前,请先完成店长的夜间模式切换动画,同时最好也要有引入Vue+Element弹窗。本动画是基于店长的样式改进的,加入了弯月,切换到夜间模式是太阳变月亮,切换到白天模式是月亮变太阳,同时背景颜色也改为了我喜欢的。)
- 
替换原来的 [BlogRoot]\themes\butterfly\source\js\sun_moon.js为以下代码,这里主要改进是由原来的after遮罩换为两个元素,再通过定时器来控制各自元素的透明度达到绘制太阳和月亮的目的: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
 75function switchNightMode() { 
 document.querySelector('body').insertAdjacentHTML('beforeend', '<div class="Cuteen_DarkSky"><div class="Cuteen_DarkPlanet"><div id="sun"></div><div id="moon"></div></div></div>'),
 setTimeout(function () {
 document.querySelector('body').classList.contains('DarkMode') ? (document.querySelector('body').classList.remove('DarkMode'), localStorage.setItem('isDark', '0'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')) : (document.querySelector('body').classList.add('DarkMode'), localStorage.setItem('isDark', '1'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')),
 setTimeout(function () {
 document.getElementsByClassName('Cuteen_DarkSky')[0].style.transition = 'opacity 3s';
 document.getElementsByClassName('Cuteen_DarkSky')[0].style.opacity = '0';
 setTimeout(function () {
 document.getElementsByClassName('Cuteen_DarkSky')[0].remove();
 }, 1e3);
 }, 2e3)
 })
 const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
 if (nowMode === 'light') {
 // 先设置太阳月亮透明度
 document.getElementById("sun").style.opacity = "1";
 document.getElementById("moon").style.opacity = "0";
 setTimeout(function () {
 document.getElementById("sun").style.opacity = "0";
 document.getElementById("moon").style.opacity = "1";
 }, 1000);
 activateDarkMode()
 saveToLocal.set('theme', 'dark', 2)
 // GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
 document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')
 // 延时弹窗提醒
 setTimeout(() => {
 new Vue({
 data: function () {
 this.$notify({
 title: "关灯啦🌙",
 message: "当前已成功切换至夜间模式!",
 position: 'top-left',
 offset: 50,
 showClose: true,
 type: "success",
 duration: 5000
 });
 }
 })
 }, 2000)
 } else {
 // 先设置太阳月亮透明度
 document.getElementById("sun").style.opacity = "0";
 document.getElementById("moon").style.opacity = "1";
 setTimeout(function () {
 document.getElementById("sun").style.opacity = "1";
 document.getElementById("moon").style.opacity = "0";
 }, 1000);
 activateLightMode()
 saveToLocal.set('theme', 'light', 2)
 document.querySelector('body').classList.add('DarkMode'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')
 setTimeout(() => {
 new Vue({
 data: function () {
 this.$notify({
 title: "开灯啦🌞",
 message: "当前已成功切换至白天模式!",
 position: 'top-left',
 offset: 50,
 showClose: true,
 type: "success",
 duration: 5000
 });
 }
 })
 }, 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)
 }
- 
替换原来的 [BlogRoot]\themes\butterfly\source\css\_layout\sun_moon.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.Cuteen_DarkSky, 
 .Cuteen_DarkSky:before
 content ''
 position fixed
 left 0
 right 0
 top 0
 bottom 0
 z-index 88888888
 .Cuteen_DarkSky
 background linear-gradient(to top, #f8cd71 0, #5bfde9 80%)
 &:before
 transition 2s ease all
 opacity 0
 background linear-gradient(to top, #30cfd0 0, #330867 100%)
 .DarkMode
 .Cuteen_DarkSky
 &:before
 opacity 1
 .Cuteen_DarkPlanet
 z-index 99999999
 position fixed
 left -50%
 top -50%
 width 200%
 height 200%
 -webkit-animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
 animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
 transform-origin center bottom
 @-webkit-keyframes CuteenPlanetMove {
 0% {
 transform: rotate(0);
 }
 to {
 transform: rotate(360deg);
 }
 }
 @keyframes CuteenPlanetMove {
 0% {
 transform: rotate(0);
 }
 to {
 transform: rotate(360deg);
 }
 }
 .Cuteen_DarkPlanet
 #sun
 position absolute
 border-radius 100%
 left 44%
 top 30%
 height 6rem
 width 6rem
 background #ffee94
 box-shadow 0 0 40px #ffee94
 // opacity 0
 #moon
 position absolute
 border-radius 100%
 left 44%
 top 30%
 position absolute
 border-radius 100%
 height 6rem
 width 6rem
 box-shadow -1.8em 1.8em 0 0.2em #fff
 // opacity 1
 // &:after
 // position absolute
 // left 42%
 // top 30%
 // width 6rem
 // height 6rem
 // border-radius 50%
 // content ''
 // background #ffef9e
 // box-shadow 0 0 30px #ffef9e
 .search
 span
 display none
 .menus_item
 a
 text-decoration none
 //按钮相关,对侧栏按钮做过魔改的可以调整这里的数值
 // .icon-V
 // padding 5px
- 
重启项目并切换夜间模式即可看到效果: 1 hexo cl; hexo s 
11 Heo同款loading动画
点击查看教程
- 本教程适用于 Butterfly 主题 4.5 以上版本(实测为 4.7.0 版本)
- 增加了动画页面下有百分比数字加载的效果
- 
修改 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
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37- loading_img = theme.preloader.avatar 
 #loading-box(onclick='document.getElementById("loading-box").classList.add("loaded")')
 .loading-bg
 img.loading-img(class='nolazyload' src=loading_img ? url_for(loading_img) : "https://cdn.staticaly.com/gh/HappyLeeCode/IMG@main/img/avatar.webp")
 .loading-image-dot
 #loading-percentage
 | 0%
 script.
 const loadingPercentage = document.getElementById("loading-percentage");
 loadingPercentage.style.color = "black";
 let loadingPercentageTimer = setInterval(function() {
 var progressBar = document.querySelector(".pace-progress");
 if (!progressBar) return
 var currentValue = progressBar.getAttribute("data-progress-text");
 if (currentValue !== loadingPercentage.textContent) {
 loadingPercentage.textContent = currentValue;
 if (currentValue === "100%") {
 clearInterval(loadingPercentageTimer);
 }
 }
 }, 100);
 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.pug1 
 2
 3
 4
 5
 6
 7if 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, 注意其中 .loading-bg 那一项下的 background 可以自行修改为自己的色值。(这里其实就是在修改加载背景的颜色,例如我的颜色是浅蓝色:#B0E2FF)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
 56if hexo-config('preloader') 
 .loading-bg
 display: flex;
 width: 100%;
 height: 100%;
 position: fixed;
 background: #B0E2FF;
 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);
 #loading-percentage
 position: absolute;
 top: 67%;
 left: 50%;
 transform: translateX(-50%);
 &::before
 content: "「"
 margin-right: 10px
 &::after
 content: "」"
 margin-left: 10px
 &.loaded
 .loading-bg
 opacity: 0;
 z-index: -1000;
 @keyframes loadingAction
 0% {
 opacity: 1;
 }
 100% {
 opacity: .4;
 }
- 
在 [BlogRoot]\source\css\custom.css中添加以下代码,其中 background 的 url 即为 loading 的图片地址。(不会的同学参考 【Hexo】添加自定义css和js文件)1 
 2
 3
 4.loading-img { 
 background: url(https://cdn.staticaly.com/gh/HappyLeeCode/IMG@main/img/avatar.webp) no-repeat center center;
 background-size: cover;
 }
- 
最后修改 _config.butterfly.yml中preloader选项, 改完以后source: 1 为满屏加载,无 pace 胶囊;source: 2 为 pace 胶囊,无满屏动画;source: 3 是两者都启用。1 
 2
 3
 4
 5
 6
 7
 8
 9# Loading Animation (加載動畫) 
 preloader:
 enable: true
 # source
 # 1. fullpage-loading
 # 2. pace (progress bar)
 source: 3
 # pace theme (see https://codebyzach.github.io/pace/)
 pace_css_url: /css/progress_bar.css
12 自定义右键菜单(自用)
点击查看教程
详见:自定义右键菜单(自用)
右键菜单前置教程:按键防抖(必须)、昼夜切换动画(本站有)、随即文章实现,请完成这两个前置教程再来做这个,或者可以注释掉pug文件中对应的功能就不会出发相应不存在的函数了。
- 
新建 [BlogRoot]\themes\butterfly\layout\includes\rightmenu.pug,编写以下内容:我这里统一采用 font-Awesome的图标,因为颜色比较统一,就没用iconfont的图标了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#rightMenu.js-pjax 
 .rightMenu-group.rightMenu-small
 a.rightMenu-item(href="javascript:window.history.back();")
 i.fa.fa-arrow-left
 a.rightMenu-item(href="javascript:window.history.forward();")
 i.fa.fa-arrow-right
 a.rightMenu-item(href="javascript:window.location.reload();")
 i.fa.fa-refresh
 a.rightMenu-item(href="javascript:rmf.scrollToTop();")
 i.fa.fa-arrow-up
 .rightMenu-group.rightMenu-line.hide#menu-text
 a.rightMenu-item(href="javascript:rmf.copySelect();")
 i.fa.fa-copy
 span='复制'
 a.rightMenu-item(href="javascript:window.open(\"https://www.baidu.com/s?wd=\"+window.getSelection().toString());window.location.reload();")
 i.fa.fa-search
 span='百度搜索'
 a.rightMenu-item(href="javascript:rmf.searchinThisPage();")
 i.fas.fa-search
 span='站内搜索'
 .rightMenu-group.rightMenu-line.hide#menu-too
 a.rightMenu-item(href="javascript:window.open(window.getSelection().toString());window.location.reload();")
 i.fa.fa-link
 span='转到链接'
 .rightMenu-group.rightMenu-line.hide#menu-paste
 a.rightMenu-item(href='javascript:rmf.paste()')
 i.fa.fa-copy
 span='粘贴'
 .rightMenu-group.rightMenu-line.hide#menu-post
 a.rightMenu-item(href="#post-comment")
 i.fas.fa-comment
 span='空降评论'
 a.rightMenu-item(href="javascript:rmf.copyWordsLink()")
 i.fa.fa-link
 span='复制本文地址'
 .rightMenu-group.rightMenu-line.hide#menu-to
 a.rightMenu-item(href="javascript:rmf.openWithNewTab()")
 i.fa.fa-window-restore
 span='新窗口打开'
 a.rightMenu-item#menu-too(href="javascript:rmf.open()")
 i.fa.fa-link
 span='转到链接'
 a.rightMenu-item(href="javascript:rmf.copyLink()")
 i.fa.fa-copy
 span='复制链接'
 .rightMenu-group.rightMenu-line.hide#menu-img
 a.rightMenu-item(href="javascript:rmf.saveAs()")
 i.fa.fa-download
 span='保存图片'
 a.rightMenu-item(href="javascript:rmf.openWithNewTab()")
 i.fa.fa-window-restore
 span='在新窗口打开'
 a.rightMenu-item(href="javascript:rmf.copyLink()")
 i.fa.fa-copy
 span='复制图片链接'
 .rightMenu-group.rightMenu-line
 a.rightMenu-item(href="javascript:randomPost()")
 i.fa.fa-paper-plane
 span='随便逛逛'
 a.rightMenu-item(href="javascript:switchNightMode();")
 i.fa.fa-moon
 span='昼夜切换'
 a.rightMenu-item(href="javascript:rmf.translate();")
 i.fa.fa-language
 span='繁简转换'
 if is_post()||is_page()
 a.rightMenu-item(href="javascript:rmf.switchReadMode();")
 i.fa.fa-book
 span='阅读模式'
 a.rightMenu-item(href="/about/")
 i.fa.fa-info-circle
 span='关于博客'
 a.rightMenu-item(href="javascript:toggleWinbox();")
 i.fas.fa-cog
 span='美化设置'
 a.rightMenu-item(href="javascript:rmf.fullScreen();")
 i.fas.fa-expand
 span='切换全屏'
 a.rightMenu-item(href="javascript:window.print();")
 i.fa-solid.fa-print
 span='打印页面'
- 
然后在 [BlogRoot]/themes/butterfly/layout/includes/layout.pug中引入(注意缩进,去掉+)1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14doctype html 
 html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside)
 head
 include ./head.pug
 body
 ...
 else
 include ./404.pug
 include ./rightside.pug
 !=partial('includes/third-party/search/index', {}, {cache: true})
 + !=partial('includes/rightmenu',{}, {cache:true})
 include ./additional-js.pug
- 
在自定义的 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/* 右键菜单 */ 
 #rightMenu {
 display: none;
 position: fixed;
 width: 160px;
 height: fit-content;
 top: 10%;
 left: 10%;
 /* 菜单面板背景色 */
 background-color: var(--card-bg);
 /* 菜单面板文字颜色 */
 border: 1px solid var(--font-color);
 border-radius: 8px;
 z-index: 100;
 }
 #rightMenu .rightMenu-group {
 padding: 7px 6px;
 }
 #rightMenu .rightMenu-group:not(:nth-last-child(1)) {
 border-bottom: 1px solid var(--font-color);
 }
 #rightMenu .rightMenu-group.rightMenu-small {
 display: flex;
 justify-content: space-between;
 }
 #rightMenu .rightMenu-group .rightMenu-item {
 height: 30px;
 line-height: 30px;
 border-radius: 8px;
 transition: 0.3s;
 color: var(--font-color);
 }
 #rightMenu .rightMenu-group.rightMenu-line .rightMenu-item {
 display: flex;
 height: 40px;
 line-height: 40px;
 padding: 0 4px;
 }
 #rightMenu .rightMenu-group .rightMenu-item:hover {
 /* 鼠标悬浮选项颜色 */
 background-color: var(--text-bg-hover);
 }
 #rightMenu .rightMenu-group .rightMenu-item i {
 display: inline-block;
 text-align: center;
 line-height: 30px;
 width: 30px;
 height: 30px;
 padding: 0 5px;
 }
 #rightMenu .rightMenu-group .rightMenu-item span {
 line-height: 30px;
 }
 #rightMenu .rightMenu-group.rightMenu-line .rightMenu-item * {
 height: 40px;
 line-height: 40px;
 }
 .rightMenu-group.hide {
 display: none;
 }
- 
创建 [BlogRoot]/themes/butterfly/source/js/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
 322function setMask() { 
 //设置遮罩
 if (document.getElementsByClassName("rmMask")[0] != undefined)
 return document.getElementsByClassName("rmMask")[0];
 mask = document.createElement('div');
 mask.className = "rmMask";
 mask.style.width = window.innerWidth + 'px';
 mask.style.height = window.innerHeight + 'px';
 mask.style.background = '#fff';
 mask.style.opacity = '.0';
 mask.style.position = 'fixed';
 mask.style.top = '0';
 mask.style.left = '0';
 mask.style.zIndex = 998;
 document.body.appendChild(mask);
 document.getElementById("rightMenu").style.zIndex = 19198;
 return mask;
 }
 function insertAtCursor(myField, myValue) {
 //IE 浏览器
 if (document.selection) {
 myField.focus();
 sel = document.selection.createRange();
 sel.text = myValue;
 sel.select();
 }
 //FireFox、Chrome等
 else if (myField.selectionStart || myField.selectionStart == '0') {
 var startPos = myField.selectionStart;
 var endPos = myField.selectionEnd;
 // 保存滚动条
 var restoreTop = myField.scrollTop;
 myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length);
 if (restoreTop > 0) {
 myField.scrollTop = restoreTop;
 }
 myField.focus();
 myField.selectionStart = startPos + myValue.length;
 myField.selectionEnd = startPos + myValue.length;
 } else {
 myField.value += myValue;
 myField.focus();
 }
 }
 let rmf = {};
 rmf.showRightMenu = function (isTrue, x = 0, y = 0) {
 let $rightMenu = $('#rightMenu');
 $rightMenu.css('top', x + 'px').css('left', y + 'px');
 if (isTrue) {
 $rightMenu.show();
 } else {
 $rightMenu.hide();
 }
 }
 rmf.copyWordsLink = function () {
 let url = window.location.href
 let txa = document.createElement("textarea");
 txa.value = url;
 document.body.appendChild(txa)
 txa.select();
 document.execCommand("Copy");
 document.body.removeChild(txa);
 }
 rmf.switchReadMode = function () {
 const $body = document.body
 $body.classList.add('read-mode')
 const newEle = document.createElement('button')
 newEle.type = 'button'
 newEle.className = 'fas fa-sign-out-alt exit-readmode'
 $body.appendChild(newEle)
 function clickFn() {
 $body.classList.remove('read-mode')
 newEle.remove()
 newEle.removeEventListener('click', clickFn)
 }
 newEle.addEventListener('click', clickFn)
 }
 //复制选中文字
 rmf.copySelect = function () {
 document.execCommand('Copy', false, null);
 }
 //回到顶部
 rmf.scrollToTop = function () {
 document.getElementsByClassName("menus_items")[1].setAttribute("style", "");
 document.getElementById("go-up").setAttribute("style", "display:none");
 btf.scrollToDest(0, 500);
 }
 rmf.translate = function () {
 document.getElementById("translateLink").click();
 }
 rmf.searchinThisPage=()=>{
 document.body.removeChild(mask);
 document.getElementsByClassName("local-search-box--input")[0].value=window.getSelection().toString()
 document.getElementsByClassName("search")[0].click()
 var evt = document.createEvent("HTMLEvents");evt.initEvent("input", false, false);document.getElementsByClassName("local-search-box--input")[0].dispatchEvent(evt);
 }
 document.body.addEventListener('touchmove', function () {
 }, { passive: false });
 function popupMenu() {
 window.oncontextmenu = function (event) {
 // if (event.ctrlKey) return true;
 // 当关掉自定义右键时候直接返回
 if (mouseMode == "off") return true;
 $('.rightMenu-group.hide').hide();
 if (document.getSelection().toString()) {
 $('#menu-text').show();
 }
 if (document.getElementById('post')) {
 $('#menu-post').show();
 } else {
 if (document.getElementById('page')) {
 $('#menu-post').show();
 }
 }
 var el = window.document.body;
 el = event.target;
 var a = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.]+$/
 if (a.test(window.getSelection().toString()) && el.tagName != "A") {
 $('#menu-too').show()
 }
 if (el.tagName == 'A') {
 $('#menu-to').show()
 rmf.open = function () {
 if (el.href.indexOf("http://") == -1 && el.href.indexOf("https://") == -1 || el.href.indexOf("yisous.xyz") != -1) {
 pjax.loadUrl(el.href)
 }
 else {
 location.href = el.href
 }
 }
 rmf.openWithNewTab = function () {
 window.open(el.href);
 // window.location.reload();
 }
 rmf.copyLink = function () {
 let url = el.href
 let txa = document.createElement("textarea");
 txa.value = url;
 document.body.appendChild(txa)
 txa.select();
 document.execCommand("Copy");
 document.body.removeChild(txa);
 }
 } else if (el.tagName == 'IMG') {
 $('#menu-img').show()
 rmf.openWithNewTab = function () {
 window.open(el.src);
 // window.location.reload();
 }
 rmf.click = function () {
 el.click()
 }
 rmf.copyLink = function () {
 let url = el.src
 let txa = document.createElement("textarea");
 txa.value = url;
 document.body.appendChild(txa)
 txa.select();
 document.execCommand("Copy");
 document.body.removeChild(txa);
 }
 rmf.saveAs = function () {
 var a = document.createElement('a');
 var url = el.src;
 var filename = url.split("/")[-1];
 a.href = url;
 a.download = filename;
 a.click();
 window.URL.revokeObjectURL(url);
 }
 } else if (el.tagName == "TEXTAREA" || el.tagName == "INPUT") {
 $('#menu-paste').show();
 rmf.paste = function () {
 navigator.permissions
 .query({
 name: 'clipboard-read'
 })
 .then(result => {
 if (result.state == 'granted' || result.state == 'prompt') {
 //读取剪贴板
 navigator.clipboard.readText().then(text => {
 console.log(text)
 insertAtCursor(el, text)
 })
 } else {
 Snackbar.show({
 text: '请允许读取剪贴板!',
 pos: 'top-center',
 showAction: false,
 })
 }
 })
 }
 }
 let pageX = event.clientX + 10;
 let pageY = event.clientY;
 let rmWidth = $('#rightMenu').width();
 let rmHeight = $('#rightMenu').height();
 if (pageX + rmWidth > window.innerWidth) {
 pageX -= rmWidth + 10;
 }
 if (pageY + rmHeight > window.innerHeight) {
 pageY -= pageY + rmHeight - window.innerHeight;
 }
 mask = setMask();
 // 滚动消失的代码和阅读进度有冲突,因此放到readPercent.js里面了
 $(".rightMenu-item").click(() => {
 $('.rmMask').attr('style', 'display: none');
 })
 $(window).resize(() => {
 rmf.showRightMenu(false);
 $('.rmMask').attr('style', 'display: none');
 })
 mask.onclick = () => {
 $('.rmMask').attr('style', 'display: none');
 }
 rmf.showRightMenu(true, pageY, pageX);
 $('.rmMask').attr('style', 'display: flex');
 return false;
 };
 window.addEventListener('click', function () {
 rmf.showRightMenu(false);
 });
 }
 if (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
 popupMenu()
 }
 const box = document.documentElement
 function addLongtabListener(target, callback) {
 let timer = 0 // 初始化timer
 target.ontouchstart = () => {
 timer = 0 // 重置timer
 timer = setTimeout(() => {
 callback();
 timer = 0
 }, 380) // 超时器能成功执行,说明是长按
 }
 target.ontouchmove = () => {
 clearTimeout(timer) // 如果来到这里,说明是滑动
 timer = 0
 }
 target.ontouchend = () => { // 到这里如果timer有值,说明此触摸时间不足380ms,是点击
 if (timer) {
 clearTimeout(timer)
 }
 }
 }
 addLongtabListener(box, popupMenu)
 // 全屏
 rmf.fullScreen = function () {
 if (document.fullscreenElement) document.exitFullscreen();
 else document.documentElement.requestFullscreen();
 }
 // 右键开关
 if (localStorage.getItem("mouse") == undefined) {
 localStorage.setItem("mouse", "on");
 }
 var mouseMode = localStorage.getItem("mouse");
 function changeMouseMode() {
 if (localStorage.getItem("mouse") == "on") {
 mouseMode = "off";
 localStorage.setItem("mouse", "off");
 debounce(function () {
 new Vue({
 data: function () {
 this.$notify({
 title: "切换右键模式成功🍔",
 message: "当前鼠标右键已恢复为系统默认!",
 position: 'top-left',
 offset: 50,
 showClose: true,
 type: "success",
 duration: 5000
 });
 }
 })
 }, 300);
 } else {
 mouseMode = "on";
 localStorage.setItem("mouse", "on");
 debounce(function () {
 new Vue({
 data: function () {
 this.$notify({
 title: "切换右键模式成功🍔",
 message: "当前鼠标右键已更换为网站指定样式!",
 position: 'top-left',
 offset: 50,
 showClose: true,
 type: "success",
 duration: 5000
 });
 }
 })
 }, 300);
 }
 }
- 
引入jQuery依赖以及上述的css和js文件( custom.css默认已经引入了就不重复引用了)1 
 2
 3
 4inject: 
 bottom:
 + - <script type="text/javascript" src="https://cdn1.tianli0.top/npm/jquery@latest/dist/jquery.min.js"></script>
 + - <script type="text/javascript" src="/js/rightmenu.js"></script>
- 
本来到这里重启项目就可以见效了,我这里还加了一个右键开关,取消了原来ctrl复合的右键开关策略。因此还需要加一个右键开关的按钮,在 [BlogRoot]\themes\butterfly\layout\includes\rightside.pug中做如下的修改,目的就是把鼠标开关放到右边栏的设置隐藏项里面,这样我们就能随时随地开关右键功能了1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15when 'comment' 
 if commentsJsLoad
 a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment"))
 i.fas.fa-comments
 + when 'mouse'
 + button.share(type="button" title='右键模式' onclick="changeMouseMode()")
 + i.fas.fa-mouse
 #rightside
 - const { enable, hide, show } = theme.rightside_item_order
 - - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode']
 + - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside', 'mouse']
 - const showArray = enable ? show && show.split(',') : ['toc','chat','share','comment']
- 
重启项目看看效果(可能会有问题,因为这个还是比较复杂的,有问题在评论区留言吧!) 1 hexo cl; hexo s 

