Github + Hexo 搭建个人博客
Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。
准备工作
基本环境
- NodeJS
- Git
- Hexo 框架
创建Github仓库
- 格式必须为:
<用户名>.github.io
,然后点击 Create repository - 生成 SSHKeys
- 检查SSH keys是否存在
1
2ls -al ~/.ssh
# Lists the files in your .ssh directory, if they exist - 生成新的ssh key
1
2ssh-keygen -t rsa -C "your_email@example.com"
#生成完成后在 C:\Users\用户名\.ssh 目录下 - 将ssh key添加到GitHub中
- 文本编辑器打开
id_rsa.pub
文件复制内容 - Github —> Settings —> SH and GPG keys —> New SSH key (Title 随意取,将内容粘贴到 Key文本框) —> Add SSH key
- 文本编辑器打开
- 测试ssh是否绑定成功:
1
ssh -T git@github.com
Hexo 初始化
- 检查SSH keys是否存在
- 安装Hexo(如已安装可跳过此步骤)
1
2
3
4
5npm install -g hexo-cli
``2. 初始化
```shell
hexo init - 初始化完成之后,打开
_config.yml
文件,添加以下配置信息1
2
3
4
5deploy:
type: git
repository: https://github.com/HaloBoys/HaloBoys.github.io.git
# github 更新之后仓库默认分支为 main
branch: main - 打开本地博客目录安装
hexo-deployer-git
自动部署发布工具1
npm install hexo-deployer-git --save
- 本地编写完博客之后输入命令:
hexo g
将md 文件转换为html文件
然后输入命令:hexo d
部署页面到远程仓库,会弹出提示框要求填写用户名和 token 令牌
Token 令牌获取路径:Settings —> Developer settings —> Personal access tokens —> Generate new token
Hexo 主题 (Butterfly)
https://github.com/jerryc127/hexo-theme-butterfly [butterfly官方文档]
功能配置
评论功能:
Gitalk
Gitalk 是一个基于 GitHub Issue 和 Preact 开发的评论插件。
- 在github上创建一个仓库,Gitalk会把评论放在这个仓库的issues里面。
- 在github上申请一个GitHub OAuth application,来让Gitalk有权限操作github上的仓库。详情GitHub 应用文档
- 打开github网站登陆后,点击右上角Settings —> Developer settings —> OAuth Apps —> New OAuth App
参数 | 描述 |
---|---|
Application name | 【必填】OAuth的名字 |
Homepage URL | 【必填】应用的网址,哪个网站用了Gitalk组件,就填写这个网址 |
Application description | 【选填】该OAuth的说明 |
Authorization callback URL | 【必填】授权成功后回调网址,跟Homepage URL参数保持一致就好 |
- 注册成功后会自动跳转到这个OAuth应用的页面,或在Developer settings —> OAuth Apps后就能看见你创建的OAuth应用名字,新创建的OAuth应用里面的
Client ID
和Client Secret
就是我们需要的参数。 - 进入主题Hexo 主题配置文件
1
2
3
4
5
6
7
8
9
10
11# gitalk
# https://github.com/gitalk/gitalk
gitalk:
client_id:
client_secret:
repo:
# 仓库的创建者
owner:
# 如果仓库有多个人可以操作,那么在这里以数组形式写出
admin:
option:Twikoo
Twikoo 是一个简洁、安全、无后端的静态网站评论系统,基于腾讯云开发。
在线聊天
Chatra
- https://chatra.com/cn/ [chatra] 直接注册账号,然后在这里将key 复制到主题_config配置文件中
- 修改主题_config配置文件
1
2
3
4
5# chatra
# https://chatra.io/
chatra:
enable: true
id: xxxxxxx // Public key - Chatra 手机/电脑 App 下载
分享功能
- https://github.com/overtrue/share.js/ [Share.js]
- https://www.addtoany.com/ [一个第三方分享服务]
- https://www.addthis.com/ [一个第三方分享服务]
网站搜索系统
- https://github.com/thom4parisot/hexo-algolia
- localsearch
- 安装 hexo-generator-search,根据官方文档去做相应配置
- 修改主题配置文件
1
2
3
4local_search:
enable: false
preload: false
CDN:
参数 | 功能 |
---|---|
enable | 是否开启本地搜索 |
preload | 预加载,开启后,进入网页后会自动加载搜索文件。关闭时,只有点击搜索按钮后,才会加载搜索文件 |
CDN | 搜索文件的 CDN 地址(默认使用的本地链接) |
文章加密
开源地址 https://github.com/D0n9X1n/hexo-blog-encrypt
- 安装
1
npm install --save hexo-blog-encrypt
- 快速使用:将
"password"
字段添加到您文章信息头就像这样再使用 hexo clean && hexo g && hexo s 在本地预览加密的文章.1
2
3
4
5---
title: Hello World
date: 2016-03-30 21:18:02
password: hello
---
对博文禁用 Tag 加密
只需要将博文头部的 password 设置为 “” 即可取消 Tag 加密.1
2
3
4
5
6
7
8
9---
title: Callback Test
date: 2019-12-21 11:54:07
tags:
- A Tag should be encrypted
password: ""
---
Use a "" to diable tag encryption.
swiper 置顶文章
- 安装插件,在博客根目录 [Blogroot] 下打开终端,运行以下指令:
1
npm install hexo-butterfly-swiper --save
- 在站点配置文件_config.yml 或者主题配置文件_config.butterfly.yml 中添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# hexo-butterfly-swiper
# see https://akilar.top/posts/8e1264d1/
swiper:
enable: true # 开关
priority: 5 #过滤器优先权
enable_page: all # 应用页面
timemode: date #date/updated
layout: # 挂载容器类型
type: id
name: recent-posts
index: 0
default_descr: 再怎么看我也不知道怎么描述它的啦!
swiper_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css #swiper css依赖
swiper_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js #swiper js依赖
custom_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css # 适配主题样式补丁
custom_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js # swiper初始化方法 - 在文章的 front_matter 中添加 swiper_index 配置项即可。
1
2
3
4
5
6
7
8---
title: 文章标题
date: 创建日期
updated: 更新日期
cover: 文章封面
description: 文章描述
swiper_index: 1 #置顶轮播图顺序,非负整数,数字越大越靠前
---
Math 数学
參考: https://butterfly.js.org/posts/ceeb73f/#Math-%E6%95%B8%E5%AD%B8 并采用 katex 数学公式方案
https://katex.org/docs/options.html
效果设置
滚动条
- 在 themes\Butterfly\source\css 文件夹新建 scrollbar.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/* 滚动条 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background-color: rgba(73, 177, 245, 0.2);
border-radius: 2em;
}
::-webkit-scrollbar-thumb {
background-color: #49b1f5 ;
background-image: -webkit-linear-gradient(
45deg,
rgba(255, 255, 255, 0.4) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.4) 50%,
rgba(255, 255, 255, 0.4) 75%,
transparent 75%,
transparent
) ;
border-radius: 2em;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
::-moz-selection {
color: #fff;
background-color: #49b1f5;
}
[data-theme="dark"] ::-webkit-scrollbar-thumb {
background-color: #1f1f1f ;
} - 编辑 _config.butterfly.yml 文件,在 inject->head 下面添加如下内容:
1
2
3inject:
head:
- <link rel="stylesheet" href="/css/scrollbar.css">
公告canvas小人
在 Butterfly/layout/includes/widget/card_announcement.pug 下添加如下代码:
1 | .xpand(style='height:200px;') |
星空背景和流星特效
- 在 [Blogroot]\themes\source\js\ 目录下新建 universe.js 输入:
1
2function 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() - 在 [Blogroot]\themes\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;
} - 在 [Blogroot]_config.butterfly.yml 的 inject 配置项中 bottom 下填入:
1
2
3
4
5inject:
bottom:
+ # 星空背景
+ - <canvas id="universe"></canvas>
+ - <script defer src="[root]/js/universe.js"></script> - 在 [Blogroot]_config.butterfly.yml 的 inject 配置项中 head 下填入:
1
2
3
4
5inject:
head:
+ # 星空背景
+ - <link rel="stylesheet" href="/css/universe.css">
---
SAO UI 风格侧栏卡片
实现效果:
- 在 [Blogroot]\themes\butterfly\source\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
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/* SAOUI字体精简包,仅73KB */
@font-face{
font-family: 'SAOUI';
src: url('https://npm.elemecdn.com/akilar-candyassets/fonts/SAOUI.ttf');
font-display: swap;
}
/* 应用于除了作者卡片以为的所有侧栏卡片 */
.card-widget:not(.card-info) {
overflow: visible ;
margin-top: 45px ;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border-top-right-radius: 10px;
border-top-left-radius: 0px ;
font-family: 'SAOUI';
color: rgba(60,60,61,0.7);
font-weight: bold;
}
/* 修复一下对侧栏电子钟的覆盖 */
.card-widget.card-clock {
overflow: hidden ;
border-radius: 8px ;
margin-top: 0px ;
}
/* 定义标题栏的定位方式为绝对定位 */
.item-headline {
font-family: 'SAOUI';
color: rgba(60,60,61,0.7);
font-weight: bold;
position: absolute;
z-index: 4;
height: 27px;
width: 65%;
top: -27px;
left: 7px;
}
/* 标题栏下各元素的层级,保证它们能显示在伪类之上 */
.item-headline i {
position: relative;
top: 0px;
margin-left: 5%;
z-index: 2;
}
.item-headline span {
position: relative;
top: 0px;
z-index: 2;
}
.item-headline a {
position: relative;
top: 0px;
z-index: 2;
}
/* 梯形伪类 */
.item-headline:after {
content: '';
position: absolute;
top: -3px; /*卡片顶部突起上下偏移量*/
right: 0;
bottom: 0;
left: -3px; /*卡片顶部突起左右偏移量*/
z-index: 1;
background: rgba(255,255,255,0.9);
border: 1px solid rgba(255,255,255,0.9);
border-bottom: 0 solid #fff;
/* 关键形变 */
transform: perspective(20px) rotateX(3deg);
border-top-right-radius: 5px ;
border-top-left-radius: 5px ;
}
/* 下划线伪类 */
.item-headline:before {
display: block;
width: 140%;
margin-top: 2px;
height: 2px;
content: '';
background: rgba(160,159,160,0.9);
border-radius: 5px;
top: 40px;
left: 0;
position: relative;
}
/* 针对手机样式的偏移量调整 */
@media screen and (max-width: 800px) {
.item-headline {
left: 8px;
}
}
/* 夜间模式色彩适配,此处仅代表糖果屋夜间模式配色 */
[data-theme="dark"] .card-widget:not(.card-info) {
color: rgba(255,255,255,0.7) ;
}
[data-theme="dark"] .item-headline {
color: rgba(255,255,255,0.7) ;
}
[data-theme="dark"] .item-headline:after {
background: rgba(0,0,0,0.5);
border: 1px solid rgba(0,0,0,0.5);
border-bottom: 0 solid rgba(0,0,0,0.5);
}
[data-theme="dark"] .item-headline:before {
background: rgba(255,255,255,0.9);
} - 在 [Blogroot]_config.butterfly.yml 中引入
1
2
3inject:
head:
- <link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'">
昼夜转换动画
- 新建 [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\_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.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
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
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
11//- 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, 引入一下 js:
1
2
3
4inject:
head:
bottome:
- <script src="[root]/js/sun_moon.js" async></script>
Butterfly 标签文章数上下标
在 Butterfly 主题中,文章标签页和标签侧边栏都有文章标签的词云图,但仅仅用字体大小表示某个标签下的文章数量是不明显的,可以在这个基础上加上表示某个标签下文章数的上下标,其中 表示上标, 表示下标。
- 在 \themes\butterfly\scripts\helpers\page.js 找到 cloudTags 函数增加 ${tag.length} 或 ${tag.length} 可绘制表示标签文章数的上下标。
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
33hexo.extend.helper.register('cloudTags', function (options = {}) {
const theme = hexo.theme.config
const env = this
let source = options.source
const minfontsize = options.minfontsize
const maxfontsize = options.maxfontsize
const limit = options.limit
const unit = options.unit || 'px'
let result = ''
if (limit > 0) {
source = source.limit(limit)
}
const sizes = []
source.sort('length').forEach(tag => {
const { length } = tag
if (sizes.includes(length)) return
sizes.push(length)
})
const length = sizes.length - 1
source.forEach(tag => {
const ratio = length ? sizes.indexOf(tag.length) / length : 0
const size = minfontsize + ((maxfontsize - minfontsize) * ratio)
let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};`
const color = 'rgb(' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ')' // 0,0,0 -> 200,200,200
style += ` color: ${color}`
- result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}</a>`
+ result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}<sup>${tag.length}</sup></a>`
})
return result
})
Hexo 博客文章统计图
使用的是 ECharts 开源可视化库对博客的文章发布时间、文章分类、文章标签的维度绘制统计图。
- 新建 charts 页面:
在 [Blogroot]\source\ 目录下新建 charts 文件夹,并在新建的 charts 文件夹下新建 index.md 文件,添加以下内容:1
2
3
4---
title: 统计图表
date: 2022-05-01 08:00:00
--- - 引入 ECharts.js(echarts.js 必须在渲染 echarts 实例的 JavaScript 前引入)
在 [Blogroot]_config.butterfly.yml 的 inject 配置项中引入 echart.js 文件。1
2
3inject:
head:
- <script src="https://cdn.jsdelivr.net/npm/echarts@4.9.0/dist/echarts.min.js"></script> - 新建文章统计代码
在 [Blogroot]\themes\butterfly\scripts\helpers\ 目录下新建 charts.js 文件,然后添加以下内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346const cheerio = require('cheerio')
const moment = require('moment')
hexo.extend.filter.register('after_render:html', function (locals) {
const $ = cheerio.load(locals)
const post = $('#posts-chart')
const tag = $('#tags-chart')
const category = $('#categories-chart')
const htmlEncode = false
if (post.length > 0 || tag.length > 0 || category.length > 0) {
if (post.length > 0 && $('#postsChart').length === 0) {
if (post.attr('data-encode') === 'true') htmlEncode = true
post.after(postsChart(post.attr('data-start')))
}
if (tag.length > 0 && $('#tagsChart').length === 0) {
if (tag.attr('data-encode') === 'true') htmlEncode = true
tag.after(tagsChart(tag.attr('data-length')))
}
if (category.length > 0 && $('#categoriesChart').length === 0) {
if (category.attr('data-encode') === 'true') htmlEncode = true
category.after(categoriesChart())
}
if (htmlEncode) {
return $.root().html().replace(/&#/g, '&#')
} else {
return $.root().html()
}
} else {
return locals
}
}, 15)
function postsChart (startMonth) {
const startDate = moment(startMonth || '2020-01')
const endDate = moment()
const monthMap = new Map()
const dayTime = 3600 * 24 * 1000
for (let time = startDate; time <= endDate; time += dayTime) {
const month = moment(time).format('YYYY-MM')
if (!monthMap.has(month)) {
monthMap.set(month, 0)
}
}
hexo.locals.get('posts').forEach(function (post) {
const month = post.date.format('YYYY-MM')
if (monthMap.has(month)) {
monthMap.set(month, monthMap.get(month) + 1)
}
})
const monthArr = JSON.stringify([...monthMap.keys()])
const monthValueArr = JSON.stringify([...monthMap.values()])
return `
<script id="postsChart">
var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
var postsChart = echarts.init(document.getElementById('posts-chart'), 'light');
var postsOption = {
title: {
text: '文章发布统计图',
x: 'center',
textStyle: {
color: color
}
},
tooltip: {
trigger: 'axis'
},
xAxis: {
name: '日期',
type: 'category',
boundaryGap: false,
nameTextStyle: {
color: color
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
},
data: ${monthArr}
},
yAxis: {
name: '文章篇数',
type: 'value',
nameTextStyle: {
color: color
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
}
},
series: [{
name: '文章篇数',
type: 'line',
smooth: true,
lineStyle: {
width: 0
},
showSymbol: false,
itemStyle: {
opacity: 1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 165)'
},
{
offset: 1,
color: 'rgba(1, 191, 236)'
}])
},
areaStyle: {
opacity: 1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 165)'
}, {
offset: 1,
color: 'rgba(1, 191, 236)'
}])
},
data: ${monthValueArr},
markLine: {
data: [{
name: '平均值',
type: 'average',
label: {
color: color
}
}]
}
}]
};
postsChart.setOption(postsOption);
window.addEventListener('resize', () => {
postsChart.resize();
});
</script>`
}
function tagsChart (len) {
const tagArr = []
hexo.locals.get('tags').map(function (tag) {
tagArr.push({ name: tag.name, value: tag.length })
})
tagArr.sort((a, b) => { return b.value - a.value })
const dataLength = Math.min(tagArr.length, len) || tagArr.length
const tagNameArr = []
const tagCountArr = []
for (let i = 0; i < dataLength; i++) {
tagNameArr.push(tagArr[i].name)
tagCountArr.push(tagArr[i].value)
}
const tagNameArrJson = JSON.stringify(tagNameArr)
const tagCountArrJson = JSON.stringify(tagCountArr)
return `
<script id="tagsChart">
var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
var tagsChart = echarts.init(document.getElementById('tags-chart'), 'light');
var tagsOption = {
title: {
text: 'Top ${dataLength} 标签统计图',
x: 'center',
textStyle: {
color: color
}
},
tooltip: {},
xAxis: {
name: '标签',
type: 'category',
nameTextStyle: {
color: color
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
},
data: ${tagNameArrJson}
},
yAxis: {
name: '文章篇数',
type: 'value',
splitLine: {
show: false
},
nameTextStyle: {
color: color
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
}
},
series: [{
name: '文章篇数',
type: 'bar',
data: ${tagCountArrJson},
itemStyle: {
borderRadius: [5, 5, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 165)'
},
{
offset: 1,
color: 'rgba(1, 191, 236)'
}])
},
emphasis: {
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 195)'
},
{
offset: 1,
color: 'rgba(1, 211, 255)'
}])
}
},
markLine: {
data: [{
name: '平均值',
type: 'average',
label: {
color: color
}
}]
}
}]
};
tagsChart.setOption(tagsOption);
window.addEventListener('resize', () => {
tagsChart.resize();
});
tagsChart.on('click', 'series', (event) => {
let href = '/tags/' + event.name + '/';
window.location.href = href;
});
</script>`
}
function categoriesChart () {
const categoryArr = []
hexo.locals.get('categories').map(function (category) {
categoryArr.push({ name: category.name, value: category.length })
})
categoryArr.sort((a, b) => { return b.value - a.value });
const categoryArrJson = JSON.stringify(categoryArr)
return `
<script id="categoriesChart">
var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
var categoriesChart = echarts.init(document.getElementById('categories-chart'), 'light');
var categoriesOption = {
title: {
text: '文章分类统计图',
x: 'center',
textStyle: {
color: color
}
},
legend: {
top: 'bottom',
textStyle: {
color: color
}
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
series: [{
name: '文章篇数',
type: 'pie',
radius: [30, 80],
center: ['50%', '50%'],
roseType: 'area',
label: {
color: color,
formatter: '{b} : {c} ({d}%)'
},
data: ${categoryArrJson},
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(255, 255, 255, 0.5)'
}
}
}]
};
categoriesChart.setOption(categoriesOption);
window.addEventListener('resize', () => {
categoriesChart.resize();
});
categoriesChart.on('click', 'series', (event) => {
let href = '/categories/' + event.name + '/';
window.location.href = href;
});
</script>`
} - 使用统计图
在 [Blogroot]\source\charts\index.md 文件中添加以下内容:1
2
3
4
5
6
7
8
9// posts-chart 的 data-start="2021-01" 属性表示文章发布时间统计图仅显示 2021-01 及以后的文章数据。
// tags-chart 的 data-length="10" 属性表示仅显示排名前 10 的标签。
<!-- 文章发布时间统计图 -->
<div id="posts-chart" data-start="2021-01" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
<!-- 文章标签统计图 -->
<div id="tags-chart" data-length="10" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
<!-- 文章分类统计图 -->
<div id="categories-chart" style="border-radius: 8px; height: 300px; padding: 10px;"></div> - 安装
cheerio
插件:在根目录执行:1
npm i cheerio --save
GitHub 贡献度
- 安装插件 hexo-github-calendar
1
npm i hexo-githubcalendar --save
- 打开 Hexo 的站点配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19githubcalendar:
enable: true
enable_page: / # 表示只在根目录(首页)显示
user: xxx # 替换成你 GitHub 的用户名
layout_id: recent-posts
githubcalendar_html: '<div class="recent-post-item" style="width:100%;height:auto;padding:10px;"><div id="github_loading" style="width:10%;height:100%;margin:0 auto;display: block"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50" xml:space="preserve"><path fill="#d0d0d0" d="M25.251,6.461c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615V6.461z" transform="rotate(275.098 25 25)"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"></animateTransform></path></svg></div><div id="github_container"></div></div>'
pc_minheight: 280px
mobile_minheight: 0px
# 粉色调
color: "['#ebedf0', '#fdcdec', '#fc9bd9', '#fa6ac5', '#f838b2', '#f5089f', '#c4067e', '#92055e', '#540336', '#48022f', '#30021f']"
# 橘黄色调
# color: "['#e4dfd7', '#f9f4dc', '#f7e8aa', '#f7e8aa', '#f8df72', '#fcd217', '#fcc515', '#f28e16', '#fb8b05', '#d85916', '#f43e06']"
# 翠绿色调
# color: "['#ebedf0', '#f0fff4', '#dcffe4', '#bef5cb', '#85e89d', '#34d058', '#28a745', '#22863a', '#176f2c', '#165c26', '#144620']"
# 天青色调
# color: "['#ebedf0', '#f1f8ff', '#dbedff', '#c8e1ff', '#79b8ff', '#2188ff', '#0366d6', '#005cc5', '#044289', '#032f62', '#05264c']"
api: https://python-github-calendar-api.vercel.app/api
# api: https://python-gitee-calendar-api.vercel.app/api
calendar_js: https://cdn.jsdelivr.net/gh/Zfour/hexo-github-calendar@1.16/hexo_githubcalendar.js
博客透明度设置
- 在 [Blogroot]\themes\source\css\ 目录下新建 alpha.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/* 文章页背景 */
.layout_post>#post {
/* 以下代表透明度为0.5 可以自行修改*/
opacity: .9;
}
/* 所有页面背景 */
#aside_content .card-widget,
#recent-posts>.recent-post-item,
.layout_page>div:first-child:not(.recent-posts),
.layout_post>#page,
.layout_post>#post,
.read-mode .layout_post>#post {
/* 以下代表透明度为0.5 */
opacity: .9;
}
/*侧边栏背景*/
.aside-content>.card-widget {
opacity: .9;
}
.sticky_layout {
opacity: .9;
}
/*文章页面*/
.layout>#post {
opacity: .9;
}
/*分类页面*/
.layout>#page {
opacity: .9;
}
/*时间轴页面*/
.layout>#archive {
opacity: .9;
} - 在主题配置文件 inject>head 中引入
1
2
3inject:
head:
- <link rel="stylesheet" href="[root]/css/alpha.css">
首页页码样式调整
修改 [Blogroot]\themes\butterfly\source\css_layout\pagination.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
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:root
--pagenumber-color: #ffffff
--pagenumber-current-color: #1E7EE2
--pagenumber-current-shadow-color: #104477
--pagenumber-hover-color: #1E7EE2
--pagenumber-background-color: rgba(0, 0, 0, 0.85)
[data-theme="dark"]
--pagenumber-color: #ffffff
--pagenumber-current-color: #1E7EE2
--pagenumber-current-shadow-color: #104477
--pagenumber-hover-color: #1E7EE2
--pagenumber-background-color: rgba(120, 120, 120, 0.85)
#pagination
.pagination
margin-top: 20px
text-align: center
position: relative;
a
color: var(--pagenumber-color)
&::after
content ''
position absolute
width 100%
height 35px
left 0
bottom 0
z-index -1
background-image -moz-linear-gradient(left, rgba(0, 0, 0, 0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0, 0, 0, 0) 100%)
background-image -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0, 0, 0, 0) 100%)
background-image linear-gradient(to right, rgba(0, 0, 0, 0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0, 0, 0, 0) 100%)
.page-number
&.current
background var(--pagenumber-current-color)
color var(--pagenumber-color)
padding: 9px 3px 0px 3px;
height: 40px;
&:before
content: '';
position: absolute;
top: -10px;
transform: translateX(-20px);
width: 30px;
border: 10px solid transparent;
border-bottom: 7px solid var(--pagenumber-current-shadow-color);
z-index: -1;
&:hover
&::after
display none
.layout
& > .recent-posts
.pagination
& > *
display: inline-block
margin: 0 6px
min-width: 30px
width: auto
height: 35px
line-height: 30px
padding: 4px 3px 0px 3px;
& > *:not(.space)
&:hover
background: var(--pagenumber-hover-color)
color: var(--pagenumber-color)
& > div:not(.recent-posts)
.pagination
.page-number
color: var(--pagenumber-color);
padding: 13px 5px 5px;
margin: 0 10px;
position: relative;
&:hover
color: var(--pagenumber-color)
&::after
content ''
position absolute
width 24px
height 24px
background var(--pagenumber-hover-color)
-moz-border-radius 100%
-webkit-border-radius 100%
border-radius 100%
z-index -1
left -3px
bottom 4px
margin auto
.pagination-info
position: absolute
top: 50%
padding: 20px 40px
width: 100%
transform: translate(0, -50%)
.prev_info,
.next_info
@extend .limit-one-line
color: var(--white)
font-weight: 500
.next-post
.pagination-info
text-align: right
.pull-full
width: 100%
.prev-post .label,
.next-post .label
color: var(--light-grey)
text-transform: uppercase
font-size: 90%
.prev-post,
.next-post
@extend .postImgHover
width: 50%
+maxWidth768()
width: 100%
a
position: relative
display: block
overflow: hidden
height: 150px
&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
background: $dark-black
原文件备份: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#pagination
.pagination
margin-top: 20px
text-align: center
.page-number
&.current
background: $theme-paginator-color
color: var(--white)
.pagination-info
position: absolute
top: 50%
padding: 20px 40px
width: 100%
transform: translate(0, -50%)
.prev_info,
.next_info
@extend .limit-one-line
color: var(--white)
font-weight: 500
.next-post
.pagination-info
text-align: right
.pull-full
width: 100%
.prev-post .label,
.next-post .label
color: var(--light-grey)
text-transform: uppercase
font-size: 90%
.prev-post,
.next-post
@extend .postImgHover
width: 50%
+maxWidth768()
width: 100%
a
position: relative
display: block
overflow: hidden
height: 150px
&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
background: $dark-black
.layout
& > .recent-posts
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w
& > *:not(.space)
@extend .cardHover
&:hover
background: var(--btn-hover-color)
color: var(--btn-color)
& > div:not(.recent-posts)
.pagination
.page-number
display: inline-block
margin: 0 4px
min-width: w = 24px
height: w
text-align: center
line-height: w
cursor: pointer
首页文章卡片修改
- 修改 [Blogroot]\themes\butterfly\layout\includes\mixins\post-ui.pug,将整个文件的内容替换为以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
115mixin postUI(posts)
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
.recent-post-content(class=leftOrRight)
a.article-content(href=url_for(link) title=subtitle)
//- Display the article introduction on homepage
case theme.index_post_content.method
when false
- break
when 1
.article-content-text!= article.description
when 2
if article.description
.article-content-text!= article.description
else
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.article-content-text!= expert
default
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.article-content-text!= expert
.recent-post-info
a.article-title(href=url_for(link) title=subtitle)
.article-title-link= title
.recent-post-meta
.article-meta-wrap
if (is_home() && (article.top || article.sticky > 0))
span.article-meta
i.fas.fa-thumbtack.sticky
span.sticky= _p('sticky')
span.article-meta-separator |
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
i.fas.fa-inbox
each item, index in article.categories.data
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
i.fas.fa-tag
each item, index in article.tags.data
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']
mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')
if theme.comments.card_post_count
case theme.comments.use[0]
when 'Disqus'
when 'Disqusjs'
+countBlockInIndex
a(href=full_url_for(link) + '#disqus_thread')
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment' itemprop="discussionUrl")
span.valine-comment-count(data-xid=url_for(link) itemprop="commentCount")
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(id=url_for(link))
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
.recent-post-cover
img.article-cover(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=subtitle)
if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index
备份: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
115mixin postUI(posts)
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
if post_cover && theme.cover.index_enable
.post_cover(class=leftOrRight)
a(href=url_for(link) title=title)
img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title)
.recent-post-info(class=no_cover)
a.article-title(href=url_for(link) title=title)= title
.article-meta-wrap
if (is_home() && (article.top || article.sticky > 0))
span.article-meta
i.fas.fa-thumbtack.sticky
span.sticky= _p('sticky')
span.article-meta-separator |
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
i.fas.fa-inbox
each item, index in article.categories.data
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
i.fas.fa-tag
each item, index in article.tags.data
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']
mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')
if theme.comments.card_post_count
case theme.comments.use[0]
when 'Disqus'
when 'Disqusjs'
+countBlockInIndex
a(href=full_url_for(link) + '#disqus_thread')
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment' itemprop="discussionUrl")
span.valine-comment-count(data-xid=url_for(link) itemprop="commentCount")
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(id=url_for(link))
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
//- Display the article introduction on homepage
case theme.index_post_content.method
when false
- break
when 1
.content!= article.description
when 2
if article.description
.content!= article.description
else
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
default
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index
- 修改 [Blogroot]\themes\butterfly\source\css_page\homepage.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351//default color:
:root
--recent-post-bgcolor: rgba(255, 255, 255, 0.9)
--article-content-bgcolor: #49b1f5
--recent-post-triangle: #fff
--recent-post-cover-shadow: #ffffff
[data-theme="dark"]
--recent-post-bgcolor: rgba(35,35,35,0.5)
--article-content-bgcolor: #99999a
--recent-post-triangle: #37e2dd
--recent-post-cover-shadow: #232323
.recent-posts
padding 0 15px 0 15px
.recent-post-item
margin-bottom 15px
width 100%
background var(--recent-post-bgcolor)
overflow hidden
border-radius 15px
.recent-post-info
.article-title-link
display -webkit-box
-webkit-box-orient vertical
-webkit-line-clamp 2
overflow hidden
.article-content
background var(--article-content-bgcolor)
position relative
display flex
align-items: center;
justify-content: center;
.article-content-text
transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
display -webkit-box
-webkit-box-orient vertical
-webkit-line-clamp 4
text-overflow: ellipsis
overflow hidden
color #fff
text-shadow: 1px 2px 3px #000;
.recent-post-cover
position relative
background transparent
img
&.article-cover
height 100%
width 100%
object-fit cover
.recent-post-info
align-items center
flex-direction column
position relative
background var(--recent-post-bgcolor)
display flex
color #000000
.article-title
height 50%
font-size 24px
display: flex
align-items: center
justify-content: flex-end
flex-direction: column
.article-title-link
color: var(--text-highlight-color)
transition: all .2s ease-in-out
&:hover
color: $text-hover
.recent-post-meta
height 50%
display: flex
align-items: center
justify-content: flex-start
flex-direction: column
.article-meta-wrap
font-size 12px
color #969797
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
a
color: var(--text-highlight-color)
transition: all .2s ease-in-out
color #969797
&:hover
color: $text-hover
&.ads-wrap
display: block
height: auto
@media screen and (min-width:600px)
.recent-post-item
&:hover
.recent-post-content
&.both,
&.right
transform translateX(21%)
transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&::before
transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
left: 50px;
.article-content-text
margin 20px 20px 20px 60px
&.left
transform translateX(-21%)
transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&::before
transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
right: 50px;
.article-content-text
margin 20px 60px 20px 20px
.recent-post-content
background var(--recent-post-bgcolor)
position relative
height 200px
width 130%
z-index 0
display flex
overflow hidden
border 0px solid
&::before
content: "";
width: 0;
height: 0;
background: transparent;
position: absolute;
z-index: 3;
top: calc(50% - 10px);
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
transition: all .5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&.both,
&.right
flex-direction: row;
left calc(-23.07% - 41px)
transition: all .5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&::before
left: calc(23.07% + 40px);
border-left: 6px solid var(--recent-post-triangle);
.recent-post-info
&::before
background linear-gradient(to right, var(--recent-post-cover-shadow), transparent)
left calc(100% - 1px)
.article-content
&::before
right -59px
border-left 60px solid var(--article-content-bgcolor)
.article-content-text
margin 20px 20px 20px 0px
.article-title
padding 0px 30px 0px 70px
.recent-post-meta
padding 0px 20px 0px 70px
&.left
flex-direction: row-reverse;
right 9px
transition: all .5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&::before
right: calc(23.07% + 40px);
border-right: 6px solid var(--recent-post-triangle);
.recent-post-info
&::before
background linear-gradient(to left, var(--recent-post-cover-shadow), transparent)
right calc(100% - 1px)
.article-content
&::before
left -59px
border-right 60px solid var(--article-content-bgcolor)
.article-content-text
margin 20px 0px 20px 20px
.article-title
padding 0px 70px 0px 30px
.recent-post-meta
padding 0px 70px 0px 20px
.article-content
width 30%
height 200px
left 0
align-items center
&::before
content ""
width 0
height 0
background transparent
position absolute
z-index 2
top 0
border-top 100px solid transparent
border-bottom 100px solid transparent
.recent-post-info
width 60%
height 200px
&::before
content ""
width 200px
height 200px
position absolute
z-index 1
top 0
.recent-post-meta
& > .article-meta-wrap
margin: 6px 0
color: $theme-meta-color
font-size: 90%
& > .post-meta-date
cursor: default
.sticky
color: $sticky-color
i
margin: 0 4px 0 0
.article-meta-label
if hexo-config('post_meta.page.label')
padding-right: 4px
else
display: none
.article-meta-separator
margin: 0 6px
.article-meta-link
margin: 0 4px
if hexo-config('post_meta.page.date_format') == 'relative'
time
display: none
a
color: $theme-meta-color
&:hover
color: $text-hover
text-decoration: underline
.recent-post-cover
width 40%
height 200px
@media screen and (max-width:600px)
.recent-post-item
height 400px
.recent-post-content
display flex
flex-direction: column
height 400px
.article-content
pointer-events none
order: 1;
height: 200px;
position: absolute;
width: calc(100% - 40px);
z-index: 3;
background: rgba(22,22,22,0.5);
border-top-left-radius: 15px;
border-top-right-radius: 15px;
display: none
opacity: 0
.article-content-text
height 120px
color: white;
width: 80%
.recent-post-cover
order: 2
height 200px
transition: all .5s
.recent-post-info
order: 3
height 200px
&::before
content: '';
width: 0;
height: 0;
position: absolute;
z-index: 3;
bottom: calc(100% - 4px);
left: 0;
border-bottom: 50px solid var(--recent-post-bgcolor);
border-right: 300px solid transparent;
&::after
content: '';
width: 0;
height: 0;
position: absolute;
z-index: 3;
bottom: calc(100% + 150px);
right: 0;
border-top: 50px solid var(--recent-post-bgcolor);
border-left: 300px solid transparent;
.article-title
padding: 0px 35px 0px 35px
.recent-post-meta
padding: 0px 30px 0px 30px
&:hover
.article-content
display: flex ;
animation: shutter-effect-content 0.5s 2 forwards linear
.recent-post-info
&::before
animation: shutter-effect-left 0.5s 1 ease-in-out
&::after
animation: shutter-effect-right 0.5s 1 ease-in-out
.recent-post-cover
filter blur(2px)
@keyframes shutter-effect-right {
0%{
bottom: calc(100% + 150px);
border-top: 50px solid var(--recent-post-bgcolor);
border-left: 300px solid transparent;
}
50%{
bottom: 100%;
border-top: 200px solid var(--recent-post-bgcolor);
border-left: 600px solid transparent;
}
100%{
bottom: calc(100% + 150px);
border-top: 50px solid var(--recent-post-bgcolor);
border-left: 300px solid transparent;
}
}
@keyframes shutter-effect-left {
0%{
bottom: calc(100% - 4px);
border-bottom: 50px solid var(--recent-post-bgcolor);
border-right: 300px solid transparent;
}
50%{
bottom: calc(100% - 4px);
border-bottom: 200px solid var(--recent-post-bgcolor);
border-right: 600px solid transparent;
}
100%{
bottom: calc(100% - 4px);
border-bottom: 50px solid var(--recent-post-bgcolor);
border-right: 300px solid transparent;
}
}
@keyframes shutter-effect-content {
from {
opacity: 0
}
to {
opacity: 1
}
}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#recent-posts
& > .recent-post-item:not(:first-child)
margin-top: 20px
& > .recent-post-item
@extend .cardHover
display: flex
flex-direction: row
align-items: center
overflow: hidden
height: 18em
+maxWidth768()
flex-direction: column
height: auto
&:hover
img.post_bg
transform: scale(1.1)
&.ads-wrap
display: block
height: auto
.post_cover
overflow: hidden
width: 44%
height: 100%
+maxWidth768()
width: 100%
height: 230px
img.post_bg
@extend .imgHover
&.right
order: 1
+maxWidth768()
order: 0
& >.recent-post-info
padding: 0 40px
width: 57%
+maxWidth768()
padding: 20px 20px 30px
width: 100%
&.no-cover
width: 100%
+maxWidth768()
padding: 30px 20px
& > .article-title
@extend .limit-more-line
color: var(--text-highlight-color)
font-size: 1.72em
line-height: 1.4
transition: all .2s ease-in-out
-webkit-line-clamp: 2
+maxWidth768()
font-size: 1.43em
&:hover
color: $text-hover
& > .article-meta-wrap
margin: 6px 0
color: $theme-meta-color
font-size: 90%
& > .post-meta-date
cursor: default
.sticky
color: $sticky-color
i
margin: 0 4px 0 0
.article-meta-label
if hexo-config('post_meta.page.label')
padding-right: 4px
else
display: none
.article-meta-separator
margin: 0 6px
.article-meta-link
margin: 0 4px
if hexo-config('post_meta.page.date_format') == 'relative'
time
display: none
a
color: $theme-meta-color
&:hover
color: $text-hover
text-decoration: underline
& > .content
@extend .limit-more-line
-webkit-line-clamp: 2
时钟插件
- 安装插件,在博客根目录 [Blogroot] 下打开终端,运行以下指令:
1
npm install hexo-butterfly-clock --save
- 在站点配置文件_config.yml 或者主题配置文件_config.butterfly.yml 中添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# electric_clock
# see https://akilar.top/posts/4e39cf4a/
electric_clock:
enable: true # 开关
priority: 5 #过滤器优先权
enable_page: all # 应用页面
exclude:
# - /posts/
# - /about/
layout: # 挂载容器类型
type: class
name: sticky_layout
index: 0
loading: https://npm.elemecdn.com/hexo-butterfly-clock/lib/loading.gif #加载动画自定义
clock_css: https://npm.elemecdn.com/hexo-butterfly-clock/lib/clock.min.css
clock_js: https://npm.elemecdn.com/hexo-butterfly-clock/lib/clock.min.js
ip_api: https://pv.sohu.com/cityjson?ie=utf-8
字体样式修改
不一定是 ttf 后缀,其他后缀也是完全正常的,例如 eot、otf、fon、font、ttc、woff、woff2 等.
- 首先需要下载心仪的字体。第一字体网:https://www.diyiziti.com/List/all/2 选择心仪的字体下载得到相应的字体文件,将其重命名为英文 xxx.ttf。
- 将下载好的字体包放到本地文件夹下,这里推荐新建一个 fonts 文件夹: [Blogroot]\themes\butterfly\source\fonts\ 目录下。
- 在自定义样式 custom.css 中引入字体包:
1
2
3
4
5@font-face{
font-family:'UniverseFont' ; /* 字体名自定义即可 */
src:url('/fonts/Font.ttf'); /* 字体文件路径 */
font-display : swap;
} - 在页面按
F12
,然后在控制台中进行调试。获取想应用字体元素的id/class
然后把 font-family 写进 custom.css 就可以了1
2
3
4
5
6
7
8
9
10@font-face{
font-family:'UniverseFont' ; /* 字体名自定义即可 */
src:url('/fonts/Font.ttf'); /* 字体文件路径 */
font-display : swap;
}
/* 例如 */
h1#site-title {
font-family: 'UniverseFont', sans-serif;
}
更改文章 h1~6 级标题前 icon 图标
单靠肉眼识别字体大小来判断标题等级不是件容易的事情,若 h1~6 标题使用不同图标的话,那么识别会容易许多。
1 |
|
其中
- H¹、H²、H³、H⁴、H⁵、H⁶
- H₁、H₂、H₃、H₄、H₅、H₆
- H1、H2、H3、H4、H5、H6
- icon 图标
- 阿里图标 …
1
2
3
4#article-container h1:before {
font-family: "iconfont";
content: "<Custom>"; /*阿里图标的 Unicode*/
}
补充插件
hexo-renderer-pug
pug 以及 stylus 的渲染器
1 | npm install hexo-renderer-pug hexo-renderer-stylus --save |
hexo-abbrlink
hexo-next文章链接默认的生成规则是::year/:month/:day/:title,是按照年、月、日、标题来生成的,如果文章标题是中文的话,URL链接是也会是中文,复制后的链接是一长串,非常不利于阅读,也不简洁。用此插件可以生成唯一不变的URl链接。
- 安装
1
npm install hexo-abbrlink --save
- 修改根目录站点配置文件config.yml
1
2
3
4permalink: posts/:abbrlink.html # post 参数为自己的自定义设置。比如::year/:month/:day:title/:abbrlink.html
abbrlink:
alg: crc32 #算法: crc16(default) and crc32
rep: hex #进制: dec(default) and hex - 生成完后,原md文件的Front-matter 内会增加abbrlink 字段,值为生成的ID 。这个字段确保了在我们修改了Front-matter 内的博客标题title或创建日期date字段之后而不会改变链接地址。
进阶操作
图床
PicGo + Gitee + Typora
PicGo + Github + Typora
特点:绑定 Typora 后支持直接在软件内插入图片自动上传图床。
缺点:国内访问速度慢(用的是github 作为存储仓库)
Typora 配置:
PicGo + SMMS
永久存储,图片链接支持https,可以删除上传的图片,提供多种图片链接格式。
每个图片最大5M,单次最多上传10张 。
Chrome 图床插件(不保证其稳定性)
方法:Chrome 插件市场 搜索插件名称安装即可
- 微博图床
- Bilibili图床
自定义域名
Github 自定义
之前绑定过了,现在好像忘了,看来不做笔记还是不行啊。有时间再重新操作下。
Gitee 自定义
要Pro版本才可以自定义,找了下开通Pro的入口没找到暂时被取消了
Hexo 写作命令
- 分类与子分类
1
2
3
4
5
6
7
8
9并列分类:
categories:
- [Linux]
- [Tools]
并列+子分类:
categories:
- [Linux, Hexo]
- [Tools, PHP] - 创建页面
1
2
3
4
5
6
7hexo new [layout] <title>
// hexo new post 'test'
Layout:Hexo 有三种默认布局:post、page 和 draft,创建这三种不同类型的文件时,它们将会被保存到不同的路径:
post source/_posts
page source
draft source/_drafts - 模版(Scaffold):在新建文章时,Hexo 会根据
scaffolds
文件夹内相对应的文件来建立文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16Blog\scaffolds 文件夹下新建模板编辑模板取好模板名称,然后可以执行如下命令根据模板内容建立文章
hexo new [模板名称] "文件名"
模板参数 描述 默认值
layout 布局 config.default_layout
title 标题 文章的文件名
date 建立日期 文件建立日期
updated 更新日期 文件更新日期
comments 开启文章的评论功能 true
tags 标签(不适用于分页)
categories 分类(不适用于分页)
permalink 覆盖文章网址
excerpt 纯文本的页面摘录。使用这个插件来格式化文本
disableNunjucks 启用时禁用 Nunjucks 标签 {{ }}/{% %} 和标签插件的呈现
lang 设置语言 Inherited from _config.yml - 分类和标签
1
2
3
4
5
6
7
8
9
10# 需要为文章添加多个分类,可以使用以下 list 中的方法
categories:
- [Diary, PlayStation]
- [Diary, Games]
- [Life]
此时这篇文章同时包括三个分类:
PlayStation 和 Games 分别都是父分类 Diary 的子分类
Life 是一个没有子分类的分类 - 监视文件变动
1
hexo generate --watch
- 一键三连
1
hexo clean & hexo g & hexo d
- 部署
1
2
3
4
5
6
7执行下列的其中一个命令,让 Hexo 在生成完毕后自动部署网站,两个命令的作用是相同的
hexo generate --deploy
hexo deploy --generate
简写:上面两个命令可以简写为
hexo g -d
hexo d -g