hexo+next打造精美的个人博客网站

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用hexo生成静态网页。

零、搭建hexo环境

要搭建hexo+github的个人博客,首先需要确保安装了git和node.js。

1. 安装和配置git

关于git的安装和配置请参考《Windows10安装git并连接github》,确保git安装成功并能上传文件到github仓库。

温馨提示:一定要配置好ssh key,参考的教程中有指导。

2. 安装node.js

git安装配置好后还要安装node.js,请至官网下载node.js

1759057642.png

node.js的具体安装从头到尾傻瓜式“下一步”。不过安装路径建议选择非系统盘目录。安装好后,检测PATH环境变量是否配置了Node.js,打开cmd 或者安装好git后的git bash,输入如下命令:

1
$ node --version

出现node.js的版本信息则说明安装成功。

3. 安装hexo

以上都完成后打开git bash输入:

1
$ npm install -g hexo-cli  #使用 npm 安装 Hexo

出现如下信息表示下载并安装完成。
999028275.png

5. 使用hexo

安装 Hexo 完成后,在任意目录执行下列命令,Hexo 将会在指定文件夹中新建所需要的文件:

1
2
3
$ hexo init myblog  # 初始化hexo工作区,此时myblog是工作区
$ cd myblog # 进入工作区
$ npm install # 安装hexo默认使用的一些基础包,可以不用执行,因为初始化时已经默认安装了这些基础包。但如果在初始化时安装这些基础包失败时,可以通过这条命令重新安装一遍。

💁‍♂不要输入 $#及其之后的注释内容。

新建完成后,指定文件夹的目录如下:

1
2
3
4
5
6
7
8
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes

编译并运行

1
2
$ hexo g # 编译生成静态文件
$ hexo s # 启动运行服务

执行以上命令之后,hexo就会在 public文件夹生成相关 html文件,这些文件将来都是要提交到github去的。hexo s是开启本地预览服务,打开浏览器访问 http://localhost:4000 即可看到内容,很多人会碰到浏览器一直在转圈但是就是加载不出来的问题,一般情况下是因为端口占用的缘故,可以使用:

1
$ hexo s -p port 	#自定义端口方式启动hexo服务。

其他命令:

1
2
$ hexo clean  	#清理public的内容
$ hexo n file #新建文章,file指的是markdown文章文件的名称

一、 编写文章

首先要在 myblog/source目录下创建一篇文章,命名为:name.md,如:first-article.md

或者用hexo创建一篇文章,打开git bash输入:

1
$ hexo n first_article

完成后 source/_posts目录下会多出 first-article.md文件。 如下图:

15.PNG

打开 first-article.md,修改表头后开始通过markdown语法来书写文章。 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
---
title: first_article
date: 2018-09-14 14:27:24
tags:
- 分享
- first
categories: 碎碎念
---

# 正文
哥们,这是你的第一篇文章~
[欢迎到我的主页](https://www.luoyui.top)

其中 categories是给分类栏添加分类项,或者将文章归纳到"碎碎念"分类项里;而 tags表示的是文字的标签,可以写多个,比如我写了 分享first

完成后编译并运行

1
2
$ hexo g
$ hexo s

然后浏览器访问测试博客,你会发现分类菜单和标签菜单里就会有内容显示了。

二、更换主题

可以到hexo官方主题下载主题模板。在这里我推荐使用next主题,文档齐全,社区也活跃。官网:http://theme-next.iissnan.com

下载主题包后放到 myblog/themes/ 下。比如我们要用next主题(使用对的版本是5.1.4),则可以进入 myblog/themes/目录下然后执行命令:

1
2
$ git clone https://github.com/iissnan/hexo-theme-next.git
$ mv hexo-theme-next next

然后修改 myblog/_config.yml中的 theme: landscape改为 theme: next

1297497270.png

完成后重新编译并并运行测试。

三、上传hexo到github

(1)首先要登录github创建一个 user.github.io仓库,仓库名比较特殊,如:qcmoke.github.io,此处的 qcmoke为你的github用户名,github正是通过这个仓库免费生成与该仓库名相同的域名,注意github只为每一位用户提供一个这样带有免费域名的 github page

💁‍♂说明:

除了 user.github.io这样特殊名称的仓库外,当然其他任意名称的仓库也可以设置pages服务,只是不提供域名罢了,但也能通过 user.github.io/仓库名称或者设置自定义域名的方式访问pages页面。

(2)安装git文件上传插件

1
$ npm install hexo-deployer-git --save

打开全局配置文件 myblog/_config.yml,找到 deploy并进行如下修改:

1
2
3
4
deploy:
type: git
repository: git@github.com:qcmoke/qcmoke.github.io.git
branch: master

其中repository的值是你git远程仓库的地址。

(3)提交部署

如果你上面都配置好了,发布上传很容易,只要一句命令就能搞定。

1
2
#这条命令会将public目录的文件提交上传到git远程仓库
$ hexo d

💁‍♂ 注意:

本地安装好后ssh key一定要配置好。 因为上传文件到github的过程中需要。

(4)访问 https://qcmoke.github.io进行测试

💁‍♂注意:

这个请求地址用你自己的,即 https://user.github.io

四、更换主题布局

next提供了4种布局供选择,我这里选的是Gemini。打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 Scheme Settings找到如下代码块,并在 scheme: Muse的前面添加 #,然后去掉 #scheme: Gemini前面的 #,修改后如下:

1
2
3
4
5
6
7
8
9
# ---------------------------------------------------------------
# Scheme Settings
# ---------------------------------------------------------------

# Schemes
#scheme: Muse
#scheme: Mist
#scheme: Pisces
scheme: Gemini

完成后重新编译运行测试,你会发现博客的主题布局已经变了。

五、菜单栏添加菜单选项

next默认菜单栏只有 homearchives菜单选项,你可以添加更多的菜单选项,比如这里我们添加 tagscategories。只需打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 Menu Settings找到如下图代码块,然后将 tagscategories选项前的注释符号 #去掉就能启用这两个菜单。如下图:

1.PNG

💁‍♂提示: NexT 使用的是 Font Awesome 提供的图标,可以去Font Awesome获取自定义的图标。

完成后重新编译并运行,然后浏览器输入http://localhost:4000/,你会发现多出来了两个菜单选项。如下图:

2.PNG

虽然是有了这两个菜单选项,但当你点击这些新菜单时会发现只有类似 Cannot GET /tags/这样的提示。此时你肯定会手足无措。别担心,之所以会有这样的提示,是因为next默认只启动了这两个菜单项,然并没有找到 tagscategories页面,你需要做的是创建这两个页面,创建的过程很简单,并不需要你有什么编程基础,你只需要输入以下命令hexo就能帮你生成这两个页面。

在站点根目录下打开你心爱的git bash。然后输入以下两条命令:

1
2
$ hexo n page tags
$ hexo n page categories

完成后你会发现 myblog/source/目录会出现两个文件夹,如下图:

3.PNG

打开 myblog/source/categories目录下的 index.md,修改内容为以下:

1
2
3
4
5
---
title: 分类
date: 2018-09-14 12:18:35
type: categories
---

打开 myblog/source/tags/目录下的 index.md,修改内容为以下:

1
2
3
4
5
---
title: 标签
date: 2018-09-14 12:17:57
type: tags
---

完成后重新编译并运行,此时你再打开浏览器输入http://localhost:4000/,点击 tagscategories菜单时会发现已经可以打开页面了。

六、默认中文简体显示设置

打开全局配置文件 myblog/_config.yml,搜索找到 language,改为以下:

1
language: zh-Hans

如图:

4.PNG

这里的 zh-Hans要根据 myblog/themes/next/languages目录下的语言配置文件的名称来设置,也有可能是 zh-CN。(如在此目录里打开 zh-Hans.yml文件,发现里面是简体中文,那就对了,注意:这里的文件的名称不填文件后缀名 .yml)

完成后重新编译并运行测试,效果如下:

5.PNG

七、更改博客作者名和主页地址

打开 myblog/_config.yml全局配置文件,搜索关键词 Site找到如下图的地方

7.PNG

然后修改以下三处:

1
2
3
4
title: Qcmoke's Blog  #站点名称
author: Qcmoke #作者名称

url: https://qcmoke.github.io/ #填github page的url即可

完成后重新编译并运行,效果如下图:

8.PNG

八、启用侧边栏社交链接

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 Social找到下图位置:

9.PNG

根据自身情况进行修改或者添加,注意:一定要去掉 #social:前的 #才能生效。我的如下图:

10.PNG

完成后重新编译并运行,效果如下图:

11.PNG

九、启用友情链接

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 Blog rolls找到下图位置:

12.PNG

根据自身情况进行修改或者添加,注意:一定要去掉 #links:前的 #才能生效。我的如下图

13.PNG

完成后重新编译并运行,效果如下图:

14.PNG

十、开启打赏功能

首先要将支付宝和微信的收款码图片放到 myblog/themes/next/source/images目录里。

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 reward找到下图位置:

16.PNG

根据自身情况进行修改或者添加,注意:一定去掉元素前面的 #才能生效。我的如下:

1
2
3
4
5
# Reward
reward_comment: 如果你觉得我的文章对你有帮助,你可以打赏我哦~
wechatpay: /images/wechatpay.png
alipay: /images/alipay.jpg
#bitcoin: /images/bitcoin.png

完成后重新编译并运行,浏览器访问博客时,你会发现每篇文章底部就会有打赏的小图标了。

十一、设置头像

找一张你喜欢的头像图片放入 myblog/themes/next/source/images目录中,例如我这里放了一张 logo.jpg。然后打开 myblog/themes/next/_config.yml主题配置文件。找到关键字 avatar,在后面加入 logo.jpg的路径地址(注意:是想相对路径)。如下图:

6.PNG

如果你想另外添加一个点击侧栏头像就能回到博客首页的功能,其实很简单,只需要将图片变成一个可以点击的图片链接。打开文件位置:myblog/themes/next/layout/_macro/sidebar.swig,找到如下代码块。

1
2
3
<img class="site-author-image" itemprop="image"
src="{{ url_for( theme.avatar | default(theme.images + '/avatar.gif') ) }}"
alt="{{ theme.author }}" />

将以上代码块外面添加一个指向博客主页的a标签。即修改成以下:

1
2
3
4
5
<a href="/">
<img class="site-author-image" itemprop="image"
src="{{ url_for( theme.avatar | default(theme.images + '/avatar.gif') ) }}"
alt="{{ theme.author }}" />
</a>

完成后重新编译并运行进行测试。

十二、圆形头像

打开站点下的 myblog/themes/next/source/css/_common/components/sidebar/sidebar-author.styl文件 ,在 .site-author-image选择器的末尾(右括号前)添加

1
2
border-radius: 50%;
transition: 2s all;

.site-author-image选择器右括号后另起一行,加入以下代码:

1
2
3
.site-author-image:hover{
transform: rotate(360deg);
}

或者你可以看下面的代码会更加直观。

原来的:

1
2
3
4
5
6
7
8
.site-author-image {
display: block;
margin: 0 auto;
padding: $site-author-image-padding;
max-width: $site-author-image-width;
height: $site-author-image-height;
border: $site-author-image-border-width solid $site-author-image-border-color;
}

修改后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.site-author-image {
display: block;
margin: 0 auto;
padding: $site-author-image-padding;
max-width: $site-author-image-width;
height: $site-author-image-height;
border: $site-author-image-border-width solid $site-author-image-border-color;
opacity: hexo-config('avatar.opacity') is a 'unit' ? hexo-config('avatar.opacity') : 1;

border-radius: 50%;
transition: 2s all;
}
.site-author-image:hover{
transform: rotate(360deg);
}

完成后重新编译并运行,效果如下图:

17.PNG

十三、设置浏览器标签图标

将一张图标32x32像素大小的图标favicon.jpg放入 myblog/themes/next/source/images目录里,打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 favicon,找到如下代码块,并做相应修改。

1
2
3
4
5
6
7
8
favicon:
small: /images/favicon-16x16-next.png
#medium: /images/favicon-32x32-next.png
medium: /images/favicon.jpg #浏览器标签图标在这里设置
apple_touch_icon: /images/apple-touch-icon-next.png
safari_pinned_tab: /images/logo.svg
#android_manifest: /images/manifest.json
#ms_browserconfig: /images/browserconfig.xml

完成后重新编译并运行,浏览器输入http://localhost:4000/访问你的博客,发现你的博客的浏览器标签图标已经变了。

十四、首页文章缩略描述设置

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 auto_excerpt找到如下位置:

1
2
3
auto_excerpt:
enable: false
length: 150

修改enable和length,修改后如下:

1
2
3
auto_excerpt:
enable: true
length: 10

完成后重新编译并运行,效果如下图:

18.PNG

十五、添加动态背景

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 canvas找到如下位置:

1
2
3
4
5
6
7
8
9
10
11
12
# Canvas-nest
# Dependencies: https://github.com/theme-next/theme-next-canvas-nest
canvas_nest: false

# JavaScript 3D library.
# Dependencies: https://github.com/theme-next/theme-next-three
# three_waves
three_waves: false
# canvas_lines
canvas_lines: false
# canvas_sphere
canvas_sphere: false

看你喜欢哪种动态背景风格,分别有 canvas_nestthree_wavescanvas_linescanvas_sphere四种,选择一种然后将冒号后面的 false改成 true。这里我选择的是第一种 canvas_nest,改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
#Canvas-nest
# Dependencies: https://github.com/theme-next/theme-next-canvas-nest
canvas_nest: true

# JavaScript 3D library.
# Dependencies: https://github.com/theme-next/theme-next-three
# three_waves
three_waves: false
# canvas_lines
canvas_lines: false
# canvas_sphere
canvas_sphere: false

完成后重新编译并运行,完成后你会发现博客网页已经出现好看的动态背景了。

十六、增加本地搜索功能

需要安装 hexo-generator-searchdb插件来实现这个功能,在站点的根目录下执行以下命令:

1
$ npm install hexo-generator-searchdb --save

编辑 myblog/_config.yml全局配置文件,新增以下内容到任意位置:

1
2
3
4
5
search:
path: search.xml
field: post
format: html
limit: 10000

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 local_search找到如下代码,enable默认是 false,将 enable设置为 true,如下:

1
2
local_search:
enable: true

完成后重新编译并运行,完成后你会发现博客菜单栏上已经出现了搜索项了。

十七、访问统计

next主题默认集成了一些第三方访问统计插件。其中推荐使用不蒜子统计服务或者leancloud统计服务。选择一种就行。

💁‍♂ 对比:

不蒜子统计:支持“本站访客数”、“本站总访问量”和“本文总阅读量”;暂不开放注册,没有用户 后台,不支持数据维护。

leancloud统计:只支持“本文总阅读量”统计;有用户后台,支持数据维护。

由于以上可看出各自的长短,所以酌情选择。如果不关心数据维护的话,我个人比较推荐使用不蒜子统计,因为简单易用。

1. 不蒜子统计

官网:http://busuanzi.ibruce.info

只需要打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 busuanzi_count。 将 enable的值改为 true,并对站点UV配置、站点PV配置、单页面PV进行配置。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
busuanzi_count:
# count values only if the other configs are false
enable: true
# custom uv span for the whole site
# 效果:本站访客数12345人次
site_uv: true
site_uv_header: 本站访客数
site_uv_footer: 人次
# custom pv span for the whole site
# 效果:本站总访问量12345次
site_pv: true
site_pv_header: 本站总访问量
site_pv_footer:
# custom pv span for one page only
# 效果:本文总阅读量12345次
page_pv: true
page_pv_header: 本文总阅读量
page_pv_footer:

完成后重新编译并运行,你会发现每篇博客文章和网页底部已经出现了访问统计信息了。

💁‍♂ 温馨提示:

目前不蒜子『dn-lbstatics.qbox.me』域名过期,更换域名到『busuanzi.ibruce.info』!故你可能需要修改以下文件相关信息:

编辑 myblog/themes/next/layout/_third-party/analytics/busuanzi-counter.swig,找到以下代码:

1
<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

修改为:

1
<script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

如果不蒜子又拿回原来的域名,那么再改回原来的域名吧~~~

2. leancloud统计

(1)登录leancloud官网注册账户。

💁‍♂说明:

现在leancloud官方的云服务系统是国内和国际分别运营,所以官方网址也分为国内网址和国际网址,个人建议国际的。

国内网址:https://leancloud.cn

国际网址:https://leancloud.app

(2)登录leancloud后台,然后创建应用

img

(3)创建应用完成后就得到了 appidappkey:

image-20200306103635845

(4)然后设置安全域名

将你网站首页的域名请求地址填进去即可,可以防止其他人攻击。

image-20200306103305868

如果你是一个开发爱好者,可以将本地localhost(包括端口号)添加进去,开发完成后再删除即可

(5)创建一个名称为Counter的Class,用于数据存储。

image-20200307024608388

(6)编辑 myblog/themes/next/_config.yml主题配置文件,添加将leancloud后台得到的 appidappkey填入配置中。如下:

1
2
3
4
5
6
# Show number of visitors to each article.
# You can visit https://leancloud.cn / https://leancloud.app get AppID and AppKey.
leancloud_visitors:
enable: true
app_id: 6LNbUE*********XbMMI
app_key: d2FLy*********uDWx

👀 注意:

enable要设置为true表示开启这个功能。

(7)如果和我一样使用的next版本是5.1.4,并且使用的leancloud是国际版(leancloud是国内版的可以跳过),就还要做兼容处理,因为国际版leancloud是后来才有的,以致于旧版的next不兼容。

修改 themes/next/layout/_third-party/analytics/lean-analytics.swig,将其内容替换成下面:

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
<!--切换国际版leancloud替换代码-->
{% if theme.leancloud_visitors.enable and !theme.valine.visitor %}
{# custom analytics part create by xiamo; edited by LEAFERx #}
<script>
{% if page.layout === 'post' %}
function addCount(Counter) {
var $visitors = $('.leancloud_visitors');
var url = $visitors.attr('id').trim();
var title = $visitors.attr('data-flag-title').trim();

Counter('get', '/classes/Counter', { where: JSON.stringify({ url }) })
.done(function({ results }) {
if (results.length > 0) {
var counter = results[0];
{% if theme.leancloud_visitors.betterPerformance %}
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(counter.time + 1);
{% endif %}
Counter('put', '/classes/Counter/' + counter.objectId, JSON.stringify({ time: { '__op': 'Increment', 'amount': 1 } }))
{% if not theme.leancloud_visitors.betterPerformance %}
.done(function() {
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(counter.time + 1);
})
{% endif %}
.fail(function ({ responseJSON }) {
console.log('Failed to save Visitor num, with error message: ' + responseJSON.error);
})
} else {
{% if theme.leancloud_visitors.security %}
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text('Counter not initialized! More info at console err msg.');
console.error('ATTENTION! LeanCloud counter has security bug, see how to solve it here: https://github.com/theme-next/hexo-leancloud-counter-security. \n However, you can still use LeanCloud without security, by setting `security` option to `false`.');
{% else %}
Counter('post', '/classes/Counter', JSON.stringify({ title: title, url: url, time: 1 }))
.done(function() {
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(1);
})
.fail(function() {
console.log('Failed to create');
});
{% endif %}
}
})
.fail(function ({ responseJSON }) {
console.log('LeanCloud Counter Error: ' + responseJSON.code + ' ' + responseJSON.error);
});
}
{% else %}
function showTime(Counter) {
var entries = [];
var $visitors = $('.leancloud_visitors');

$visitors.each(function() {
entries.push( $(this).attr('id').trim() );
});

Counter('get', '/classes/Counter', { where: JSON.stringify({ url: { '$in': entries } }) })
.done(function({ results }) {
var COUNT_CONTAINER_REF = '.leancloud-visitors-count';

if (results.length === 0) {
$visitors.find(COUNT_CONTAINER_REF).text(0);
return;
}

for (var i = 0; i < results.length; i++) {
var item = results[i];
var url = item.url;
var time = item.time;
var element = document.getElementById(url);

$(element).find(COUNT_CONTAINER_REF).text(time);
}
for (var i = 0; i < entries.length; i++) {
var url = entries[i];
var element = document.getElementById(url);
var countSpan = $(element).find(COUNT_CONTAINER_REF);
if (countSpan.text() == '') {
countSpan.text(0);
}
}
})
.fail(function ({ responseJSON }) {
console.log('LeanCloud Counter Error: ' + responseJSON.code + ' ' + responseJSON.error);
});
}
{% endif %}

$(function() {
$.get('https://app-router.leancloud.cn/2/route?appId=' + '{{ theme.leancloud_visitors.app_id }}')
.done(function({ api_server }) {
var Counter = function(method, url, data) {
return $.ajax({
method: method,
url: 'https://' + api_server + '/1.1' + url,
headers: {
'X-LC-Id': '{{ theme.leancloud_visitors.app_id }}',
'X-LC-Key': '{{ theme.leancloud_visitors.app_key }}',
'Content-Type': 'application/json',
},
data: data
});
};
{% if page.layout === 'post' %}
const localhost = /http:\/\/(localhost|127.0.0.1|0.0.0.0)/;
if (localhost.test(document.URL)) return;//本地调试时不进行统计
addCount(Counter);
{% else %}
if ($('.post-title-link').length >= 1) {
showTime(Counter);
}
{% endif %}
});
});
</script>

{% endif %}



<!--next原来的版本-->
<!--
{% if theme.leancloud_visitors.enable %}

{# custom analytics part create by xiamo #}
<script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script>
<script>AV.initialize("{{theme.leancloud_visitors.app_id}}", "{{theme.leancloud_visitors.app_key}}");</script>
<script>
function showTime(Counter) {
var query = new AV.Query(Counter);
var entries = [];
var $visitors = $(".leancloud_visitors");

$visitors.each(function () {
entries.push( $(this).attr("id").trim() );
});

query.containedIn('url', entries);
query.find()
.done(function (results) {
var COUNT_CONTAINER_REF = '.leancloud-visitors-count';

if (results.length === 0) {
$visitors.find(COUNT_CONTAINER_REF).text(0);
return;
}

for (var i = 0; i < results.length; i++) {
var item = results[i];
var url = item.get('url');
var time = item.get('time');
var element = document.getElementById(url);

$(element).find(COUNT_CONTAINER_REF).text(time);
}
for(var i = 0; i < entries.length; i++) {
var url = entries[i];
var element = document.getElementById(url);
var countSpan = $(element).find(COUNT_CONTAINER_REF);
if( countSpan.text() == '') {
countSpan.text(0);
}
}
})
.fail(function (object, error) {
console.log("Error: " + error.code + " " + error.message);
});
}

function addCount(Counter) {
var $visitors = $(".leancloud_visitors");
var url = $visitors.attr('id').trim();
var title = $visitors.attr('data-flag-title').trim();
var query = new AV.Query(Counter);

query.equalTo("url", url);
query.find({
success: function(results) {
if (results.length > 0) {
var counter = results[0];
counter.fetchWhenSave(true);
counter.increment("time");
counter.save(null, {
success: function(counter) {
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(counter.get('time'));
},
error: function(counter, error) {
console.log('Failed to save Visitor num, with error message: ' + error.message);
}
});
} else {
var newcounter = new Counter();
/* Set ACL */
var acl = new AV.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
newcounter.setACL(acl);
/* End Set ACL */
newcounter.set("title", title);
newcounter.set("url", url);
newcounter.set("time", 1);
newcounter.save(null, {
success: function(newcounter) {
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(newcounter.get('time'));
},
error: function(newcounter, error) {
console.log('Failed to create');
}
});
}
},
error: function(error) {
console.log('Error:' + error.code + " " + error.message);
}
});
}

$(function() {
var Counter = AV.Object.extend("Counter");
if ($('.leancloud_visitors').length == 1) {
addCount(Counter);
} else if ($('.post-title-link').length > 1) {
showTime(Counter);
}
});
</script>

{% endif %}
-->

🙉注意:本地调试时不进行统计。如果看懂上面源码可以让其在本地调试是能进行统计。但小白直接复制粘贴就好,发布部署时,通过域名访问就能统计了。

为了让移动端显示更友好,我修改了 themes/next/layout/_macro/post.swig文件,加了一个span标签进行修饰,让小眼睛和访问数值始终在同一行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
          {# LeanCould PageView #}
{% if theme.leancloud_visitors.enable %}
<span id="{{ url_for(post.path) }}" class="leancloud_visitors" data-flag-title="{{ post.title }}">
<span class="post-meta-divider">|</span>
+ <span class="lv-inline-block" style="display: inline-block;">
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
{% if theme.post_meta.item_text %}
<span class="post-meta-item-text">{{__('post.visitors')}}:</span>
{% endif %}
<span class="leancloud-visitors-count"></span>
+ </span>
</span>
{% endif %}

3. 额外补充

由于不蒜子统计和leancloud统计都存在着一些缺失的问题,但是它们之间又冥冥中有着互补的关系,所以我通过一波考虑后,选择了折中的方案,那就是使用不蒜子统计的“本站访客数”、“本站总访问量”,而使用leancloud统计的“本文总阅读量”统计。配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Show PV/UV of the website/page with busuanzi.
# Get more information on http://ibruce.info/2015/04/04/busuanzi/
busuanzi_count:
# count values only if the other configs are false
enable: true
# custom uv span for the whole site
# 效果:本站访客数12345人次
site_uv: true
site_uv_header: 本站访客数
site_uv_footer: 人次
# custom pv span for the whole site
# 效果:本站总访问量12345次
site_pv: true
site_pv_header: 本站总访问量
site_pv_footer:
# custom pv span for one page only
# 效果:本文总阅读量12345次
page_pv: false
page_pv_header: 本文总阅读量
page_pv_footer:
1
2
3
4
5
6
# Show number of visitors to each article.
# You can visit https://leancloud.cn / https://leancloud.app get AppID and AppKey.
leancloud_visitors:
enable: true
app_id: 6LNbUERxbG0OAnWfmJSbmXiW-MdYXbMMI
app_key: d2FLy9fmXOTiM8TrokuIuDWx

💁‍♂如果你对这访问统计这一块很感兴趣并且懂点编程知识的话,你完全可以通过leancloud的sdk来开发出完整的统计功能。这样的话就可以不用不蒜子统计了。要是你还有一台可以长期使用的vps的话,你甚至可以不用leancloud的服务,而是自己实现一个访问计数的后端服务。这里我就不深入了。

十八、字数统计和阅读时长功能

需要安装 hexo-wordcount这个插件来实现这个功能,在站点根目录下打开git bash,输入:

1
$ npm install hexo-wordcount --save

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 post_wordcount
将其配置修改成以下代码:

1
2
3
4
5
6
post_wordcount:
item_text: true
wordcount: true
min2read: true
totalcount: false
separated_meta: true

完成后重新编译并运行测试。

十九、隐藏底部的“强力驱动”内容

打开 myblog/themes/next/layout/_partials/footer.swig,搜索关键字 theme.footer.powered.enable,通过 <!-- -->注释掉如下代码。
19.PNG

完成后重新编译并运行,你会发现博客已经隐藏掉了底部的“强力驱动”内容了。

二十、文章分享功能

这里我提供了三种方案,推荐下文说的第二种方案。

方案1 jiathis

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 jiathis,找到如下代码。

1
2
3
#jiathis:
##uid: Get this uid from http://www.jiathis.com/
#add_this_id:

去掉 #jiathis:前的 #,并在其后添加 true结果如下:

1
2
3
jiathis: true
##uid: Get this uid from http://www.jiathis.com/
#add_this_id:

不知道为什么有bug,无法加载出图标,也不能点击。于是恢复原样后,改用第二种方案。

方案2 needmoreshare2

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 needmoreshare2,找到如下代码并做以下修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
needmoreshare2:
enable: true
postbottom:
enable: true
options:
iconStyle: box
boxForm: horizontal
position: bottomCenter
networks: Weibo,Wechat,Douban,QQZone,Twitter,Facebook
float:
enable: true
options:
iconStyle: box
boxForm: horizontal
position: middleRight
networks: Weibo,Wechat,Douban,QQZone,Twitter,Facebook

不过我发现next 5.1.4版本中微信加载不出二维码,应该是封装好的微信分享链接失效了。我是通过老版本的仓库https://github.com/iissnan/hexo-theme-next安装的,所以有这个问题,而新版本的next是没有这个问题的。新版本仓库已经搬迁到了https://github.com/theme-next 。

虽然我安装的是老版本,不过这里我也提供了解决办法。站点根目录下打开git bash,输入以下命令:

1
2
$ rm -rf themes/next/source/lib/needsharebutton
$ git clone https://github.com/theme-next/theme-next-needmoreshare2 themes/next/source/lib/needsharebutton

完成后重新编译并运行,你会发现博客已经出现分享服务图标了,并且点击微信分享图标也可以加载出分享二维码了。

方案3 baidushare

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 baidushare,找到如下代码并做修改。修改后如下:

1
2
3
4
5
#baidushare:
## type: button
baidushare:
type: button
baidushare: true

完成后重新编译并运行,你会发现博客已经出现分享服务图标了。

二十一、文章应用本地图片

这里我可能比较废话,你可以跳过以下几段文字直接进行插件安装和配置。但想知道问题解决的思路,还是值得看看的。

写博客时虽然可以通过第三方图床给hexo文章插入图片,但如果你和我一样总害怕哪天第三方图床提供商被无故和谐了或者关闭服务了,那么通过相对路径从本地引入图片的方案无疑是种再好不过的方案。hexo允许你在 myblog/source/images目录下放入图片(这里的images目录如果没有需要你自己创建),当hexo编译时会将图片放入到 myblog/public/images目录里。由于部署博客其实就是部署 public目录,所以引用图片的方式也就是 ![](/images/image.jpg)。因此要将博客文章引用的本地图片都存到 myblog/source/images目录里。但所有的图片都放到同一个目录里,当后期的本地图片越来越多,维护的成本也就随着越来越大了。

由于以上的问题,hexo也支持通过其他目录的方式引入图片,只要修改 myblog/_config.yml全局配置文件,将 post_asset_folder:这个选项设置为 true,然后创建markdown文章,比如通过 hexo new articlemyblog/source/_posts创建了一篇 article.md文章和同名文件夹 article,我们可以将图片 image.jpg放到这个文件夹里,在 article.md文章里通过类似 ![](2018/09/21/article/image.jpg)的方式来引用图片( 此处的 2018/09/21/article是经hexo静态处理后文章和图片的存放路径,这个路径第一次编译该markdown文件的日期来生成的) 。但这样的处理导致我们在后期写markdown文章引用图片的时候必须要记住这个日期,这是很糟糕的!这也就算了,我们往往是通过markdown工具来编辑博客文章的,如果在编辑前未经过编译,hexo还未将图片转移到 2018/09/21/article/目录下,通过 ![](2018/09/21/article/image.jpg)的方式插入图片,markdown工具根本无法加载出图片。

由于以上种种让人想破口大骂的痛点,引发了我的一个思路,我的思路是让每篇markdown文章的图片都放在文章所在目录的同名目录里(比如文章是 myblog/source/_posts/article.md,那么同名目录是 myblog/source/_posts/article),而在 article.md中可以使用 ![](article/image.jpg)的方式来引用图片,最终经过hexo编译后图片仍然与生成静态文件的 html文章保持原有的相对路径,而不会出现上文中那一大串日期路径,这是我一直想要实现的,但遗憾的是我没找到hexo对该方案的支持。后来我找到了一个很给力的插件 hexo-asset-image,它能实现我上文提出的思路,下面就奉上教程。

(1)安装hexo-asset-image

1
$ npm install hexo-asset-image --save

(2)将全局配置文件 myblog/_config.yml里的 post_asset_folder:这个选项设置为 true

(3)新建一篇markdown文章做测试

1
2
#执行该命令会在myblog/source/_posts/文件夹内除了生成newpage.md文件外,还生成一个同名的newpage文件夹
$ hexo n newpage

(4)引用本地图片

要插入图片时,只需要将图片放入 newpage文件夹中,比如放入一张名为test.png的图片,那么在newpage.md中通过以下markdown语句来引用该图片:

1
![test](newpage/test.png)

(5)编译并启动测试

1
2
$ hexo g
$ hexo s

完成后你会发现博客中相关的文章能正常显示图片了。

💁‍♂ 我在另一篇文章做了一些更优的扩展,可以参考 https://qcmoke.site/blog/hexo_seo.html

二十二、让hexo支持emoji

如何让markdown可以解析emoji呢?实际上我们发现,在一些编辑器中输入 :blush: 并没有表情出现(当然有的编辑器可以,比如我现在使用的typora就很给力),这是为什么呢? 这是markdown编辑器渲染引擎的问题 。同样的,Hexo也要对markdown文件进行渲染,而Hexo目前默认渲染引擎是 hexo-renderer-marked,可惜这个渲染器似乎不支持插件扩展,当然就不行了。那怎么解决呢?这里就要说 hexo-renderer-markdown-it插件了,这个渲染器插件是支持扩展,我们可以使用这个渲染引擎来支持 emoji表情,具体实现过程如下:

  • 更换渲染器

    进入blog跟目录,执行如下命令

1
2
$ npm un hexo-renderer-marked --save           #卸载hexo默认渲染器hexo-renderer-marked
$ npm i hexo-renderer-markdown-it --save #安装渲染器hexo-renderer-markdown-it
  • 安装emoji插件,执行如下命令
1
$ npm install markdown-it-emoji --save
  • 编辑站点配置文件
    打开 myblog/_config.yml站点配置文件,添加如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Markdown-it config
## Docs: https://github.com/celsomiranda/hexo-renderer-markdown-it/wiki
markdown:
render:
html: true
xhtmlOut: false
breaks: true
linkify: true
typographer: true
quotes: '“”‘’'
plugins:
- markdown-it-abbr
- markdown-it-footnote
- markdown-it-ins
- markdown-it-sub
- markdown-it-sup
- markdown-it-emoji # add emoji
anchors:
level: 2
collisionSuffix: 'v'
permalink: true
permalinkClass: header-anchor
permalinkSymbol:

完成后重新编译并运行,你会发现博客中相关的文章能正常显示 emoji表情了。比如下面的markdown经过编译成html后,网页访问会得到这个笑脸:😄

1
2
3
4
5
6
7
---
title: emoji test
date: 2018-09-14 04:13:00
---
<!-- more -->

:smile:

💁‍♂更多的 emoji写法可参考:

📚https://www.webfx.com/tools/emoji-cheat-sheet/

二十三、加入评论面板

1. Gitalk

上网找过很多与hexo相关的评论面板,但发现很多第三方的评论面板提供的评论面板都有一个致命的弱点,那就是在不可预料的一天突然在国内被和谐了,或者出现各种各样的问题,这很让人头疼。后来在网上发现有人通过调用github提供的Issues api做成了比较美观的评论面板,这其中我发现了两种,第一种是gitment,第二种就是这里要讲的gitalk。之前也尝试过加入gitment,但是发现装好后出现了各种问题。最严重的问题就是无法通过登陆评论面板进行初始化文章的评论功能,所以也就放弃了这种途径。后来在next的Telegram群里发现了gitalk这个干货,于是开始上网找各种教程尝试搭建,但在这过程中也还是发现了一些问题。所以在这里我将尽可能详细解释清楚,避免误导大家。

(1)首先你得先到github上申请一个 Github Application,由于需要调用 Github API ,首先点击注册一个 Github Application 。

申请页如下图:

1537368382709.png

参数说明:

1
2
3
4
Application name:          #应用名称,随意填
Homepage URL: #应用地址,填你的博客地址,如https://youname.github.io
Application description #描述,随意填
Authorization callback URL:#回调地址,填你的博客地址,如https://youname.github.io

如果没有用自购的域名,Homepage URLAuthorization callback URL统一填https://youname.github.io (youname是你的github用户名)。

填写完成后,点击register application。

创建成功后,会看到 clientID: XXXclientSecret: XXX 这两个参数,如下图:

1537370272870.png

(2)创建一个仓库用来存放issue数据,命名可以随意,但为了和我统一,最好也命名为 gitalk

(3)添加gitalk.swig配置文件

在目录 myblog/themes/next/layout/_third-party/comments下创建一个 gitalk.swig文件。

将以下代码全部复制到 gitalk.swig中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% if theme.gitalk.enable %}
{% if page.comments %}
<link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
<script type="text/javascript">
const gitalk = new Gitalk({
clientID: '{{theme.gitalk.clientID}}',
clientSecret: '{{theme.gitalk.clientSecret}}',
repo: '{{theme.gitalk.repo}}',
owner: '{{theme.gitalk.owner}}',
admin: '{{theme.gitalk.admin}}'.split(','),
id: location.pathname,
// facebook-like distraction free mode
distractionFreeMode: '{{ theme.gitalk.distractionFreeMode }}',
createIssueManually: '{{ theme.gitalk.createIssueManually }}'
})
gitalk.render('gitalk-container')
</script>
{% endif %}
{% endif %}

(4)修改index.swig配置文件

myblog/themes/next/layout/_third-party/comments目录下的 index.swig文件最后加入以下代码:

1
{% include 'gitalk.swig' %}

(5)修改comments.swig配置文件

打开 myblog/themes/next/layout/_partials 目录下的 comments.swig文件,搜索关键字 valine找到以下代码:

1
2
3
4
{% elseif theme.valine.appid and theme.valine.appkey %}
<div class="comments" id="comments">
</div>
{% endif %}

将以上代码改成以下代码:

1
2
3
4
5
6
7
8
{% elseif theme.valine.appid and theme.valine.appkey %}
<div class="comments" id="comments">
</div>
{% elseif theme.gitalk.enable %}
<div class="comments" id="comments">
<div id="gitalk-container"></div>
</div>
{% endif %}

(6)修改主题配置文件

打开 myblog/themes/next/_config.yml主题配置文件,根据自己的情况添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
# Gitalk
# more info please open https://github.com/gitalk/gitalk
gitalk:
enable: true
clientID: d933e443cdfe503ce05a #创建Github Application时生成的clientID
clientSecret: 149d163f4b10cedf7a68993289da9c0f0836bd34 #创建Github Application时生成的clientSecret
repo: mygitalk #填之前创建好的存放issue的仓库名
owner: qcmoke #填Github 用户名
admin: qcmoke #填Github 用户名
distractionFreeMode: true #类似Facebook评论框的全屏遮罩效果.
createIssueManually: true #如果当前页面没有相应的 isssue ,且登录的用户属于 admin,则会自动创建 issue。如果设置为 true,则显示一个初始化页面,创建 issue 需要点击 init 按钮。

为了不出错同时也方便管理,你可将这些代码放在gitment(如果之前有配置的话)板块后。如我的:

1537366863938.png

(7)部署到github

最后通过 hexo 部署你的博客,即可看到gitalk评论面板的效果。

1537367186506.png

(8)初始化每篇文章的Issue

你可能会发现还不能评论,很简单,你只需要点击 初始化Issue,之后就要以github账号登录。登录成功后便自动完成初始化。(注意,只能通过自己的github账号来初始化)。初始化需要刷新一下,结果如下图,github用户就能通过登录github账号进行评论了。

1537367817100.png

同时存放评论数据的仓库,Issues下也生成了Issue数据

1537367920673.png

至此,加入Gitalk评论面板完结。

2. Vssue

目前发现Gitalk是很好的,但是目前它只支持github代码托管平台,但碍于github服务器在国外,评论面板有时候会由于网络的原因导致无法请求api,所以这才认识到了Vssue,Vssue和Gitalk的功能差不多,它支持多个代码托管平台(GitHub、GitLab、Bitbucket、Gitee、Gitea),如果使用Gitee作为评论api的话,网络延时的问题就会得到比较好的解决。接下来就奉上教程。

(1)在目录 myblog/themes/next/layout/_third-party/comments下创建一个 vssue.swig文件。内容如下:

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
{% if theme.vssue.enable %}
{% if page.comments %}
<!-- Vssue 的样式文件 -->
<link rel="stylesheet" href="{{ theme.vssue.vssueCss }}">
<!-- Vue 运行时版 (runtime only) -->
<script src="{{ theme.vssue.vueRuntimeJs }}"></script>
<!-- 在 Vue 之后引入 Vssue -->
<script src="{{ theme.vssue.vssueTypeJs }}"></script>
<!-- 将 Vssue 作为 Vue 组件使用,对于 Vue 运行时版,使用渲染函数(render function) -->
<script type="text/javascript">
new Vue({
el: '#vssue',
render: h => h('Vssue', {
props: {
// 在这里设置当前页面对应的 Issue 标题
title: '{{theme.vssue.title}}',
// 在这里设置你使用的平台的 OAuth App 配置
options: {
owner: '{{theme.vssue.owner}}',
repo: '{{theme.vssue.repo}}',
clientId: '{{theme.vssue.clientId}}',
clientSecret: '{{theme.vssue.clientSecret}}',
},
}
})
})
</script>

<!--自定义样式-->
<style>
.vssue {
width: 96%;
color: #60676d;
}
.vssue .vssue-button {
padding: unset;
}
.vssue .vssue-button:not(:disabled).vssue-button-primary {
color: #60676d;
border-color: #60676d;
}
.vssue :not(.vssue-comment-content) a {
color: #333;
}
</style>
{% endif %}
{% endif %}

(2)在 myblog/themes/next/layout/_third-party/comments目录下的 index.swig文件最后加入以下代码:

1
{% include 'vssue.swig' %}

(3)打开 myblog/themes/next/layout/_partials 目录下的 comments.swig文件,添加如下 +的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   {% elseif theme.valine.appid and theme.valine.appkey %}
<div class="comments" id="comments"></div>

{% elseif theme.gitalk.enable %}
<div class="comments" id="comments">
<div id="gitalk-container"></div>
</div>

+ {% elseif theme.vssue.enable %}
+ <div class="comments" id="comments">
+ <div id="vssue"></div>
+ </div>

{% endif %}

{% endif %}

(4)修改主题配置文件

打开 myblog/themes/next/_config.yml主题配置文件,根据自己的情况添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## Vssue
# more info please open https://vssue.js.org
vssue:
enable: true #是否开启vssue评论面板
owner: qcmoke #git管理用户
repo: myvssue #git仓库名称
title: Vssue Dev #对应的Issue标题
clientId: b0634**********1012aa #OAuth App clientId
clientSecret: 7a3********620313 #OAuth App clientSecret
#Vssue js文件(支持多个代码托管平台,切换平台时要切换相应的js文件)
#GitHub:https://unpkg.com/vssue/dist/vssue.github.min.js
#GitLab:https://unpkg.com/vssue/dist/vssue.gitlab.min.js
#Bitbucket:https://unpkg.com/vssue/dist/vssue.bitbucket.min.js
#Gitee:https://unpkg.com/vssue/dist/vssue.gitee.min.js
#Gitea:https://unpkg.com/vssue/dist/vssue.gitea.min.js
vssueTypeJs: https://unpkg.com/vssue/dist/vssue.gitee.min.js
vssueCss: https://unpkg.com/vssue/dist/vssue.min.css #Vssue 的样式文件
vueRuntimeJs: https://unpkg.com/vue/dist/vue.runtime.min.js #Vue 运行时版 (runtime only)

至此,加入Vssue评论面板完结。

💁‍♂ 提示:

clientId和clientSecret和Gitalk的申请差不多,可以自行去相应的git代码托管平台进行申请。当然我推荐你去参考非常详细的官方指南:https://vssue.js.org/zh/guide

3. Valine

3.1 普通版Valine

valine是一个优秀的评论系统软件,后台的评论数据依赖于leancloud的云存储,所以还需要去leancloud官网设置数据存储功能。

(1)首先就是去leancloud获取 appidappkey,怎么获取可以参考上文中的"访问统计=>leandcloud统计”。

💁‍♂提示: 其中 appidappkey与leandcloud统计一样就行。

(2)另外,还需要在leancloud后台创建一个Comment的Class,用于数据存储。

image-20200306115321197

虽然网上有人说valine会自动创建这个Class,但是我在用国际版测试的时候发现一直无权限或者提示没这个Class,那倒不如直接创建就好。

(3)修改主题配置文件,配置 valine。修改 enabletrue,并且添加 appidappkey即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
# Valine.
# You can get your appid and appkey from https://leancloud.cn
# more info please open https://valine.js.org
valine:
enable: true
appid: 75OSy9**********zoHsz # your leancloud application appid
appkey: LKk**************GeB # your leancloud application appkey
notify: false # mail notifier , https://github.com/xCss/Valine/wiki
verify: false # Verification code
placeholder: Just go go # comment box placeholder
avatar: mm # gravatar style
guest_info: nick,mail,link # custom comment header
pageSize: 10 # pagination size

💁‍♂说明:

avatar 是设置默认头像,可以去https://valine.js.org/avatar 选择默认头像

更多详细内容请查阅valine的官方文档:https://valine.js.org

3.2 增强版valine

原生的普通版valine功能比较少,但由于其优秀的设计和适用场景,得到了很多开发者的青睐,因此网上出现了一些增强版的valine,这里推荐Deserts的valine版本,它除了可以做基本的评论外,还有一些比较高级的功能,比如邮件通知,后台数据管理等功能。

📚 官方文档:https://deserts.io/diy-a-comment-system

📦 项目地址:https://github.com/DesertsP/Valine-Admin

为了适配hexo next,请按照如下步骤修改:

(1)先下载相关sdk文件,放到 themes/next/source/js/src下。

⬇️官方下载地址:

下载Valine.min.js:https://github.com/DesertsP/Valine/releases

下载av-min.js:https://code.bdstatic.com/npm/leancloud-storage@4.12.0/dist/av-min.js

(2)然后修改 themes/next/layout/_third-party/comments/valine.swig

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
{% if theme.valine.enable %}
{% if page.comments %}
<!--Leancloud 操作库-->
<script src="/js/src/av-min.js"></script>
<!--Valine 的核心代码库-->
<script src="/js/src/Valine.min.js"></script>

<script type="text/javascript">
var emoticonList=[]
for(var i = 1; i <= 164; i++){
emoticonList.push("aru ("+i+").png")
}
new Valine({
lang: 'zh-cn',
admin_email: 'qcmoke@gmail.com',
el: '#comments-valine' ,
appId: '{{ theme.valine.appid }}',
appKey: '{{ theme.valine.appkey }}',
//表情图片目录地址
emoticon_url: 'https://cdn.jsdelivr.net/gh/Sanarous/files/emojis/aru',
//表情图片目录的图片名称列表
emoticon_list: emoticonList,
placeholder: '{{ theme.valine.placeholder }}',
});
</script>


<script>
//点击邮件中的链接跳转至相应评论
if(window.location.hash){
var checkExist = setInterval(function() {
if ($(window.location.hash).length) {
$('html, body').animate({scrollTop: $(window.location.hash).offset().top-90}, 1000);
clearInterval(checkExist);
}
}, 100);
}
</script>
{% endif %}
{% endif %}

这样就可以基本替代原版了,基本的评论评论功能已经可以正常使用。但如果想要一些增强功能,比如后台评论数据管理、邮件提醒和通知等,那么还需要花一些时间操作的。具体请参考官方文档完成这些工作。

官方文档:

📚 https://deserts.io/diy-a-comment-system

📚 https://deserts.io/valine-admin-document

由于官方文档中的教程已经很详细了,跟着操作基本就能完成。下面只介绍一些额外的说明:

(1)关于自定义环境变量

直接参考我下面的可以尽量避免出错。下面附上我的leancloud管理后台自定义环境变量:

image-20200307175642685

💁‍♂补充说明:

(1)我配置的smtp账号和密码是Gmail的,当然还可以使用其他的,比如QQ,Outlook等,具体可参考这篇文章:http://help.cy-email.com/yxtj-cyyx

(2)如果机器正在启动然后就修改这些环境变量的话是需要到“部署”那里重启的。

(3)有几个邮件模板环境变量图片中显示不全,下面是完整的。

MAIL_SUBJECT

1
${PARENT_NICK},您在『${SITE_NAME}』上的评论收到了回复

MAIL_TEMPLATE

1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px;color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您在<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}">『${SITE_NAME}』</a>上的留言有新回复啦!!!</p></div><div style="margin:40px auto;width:90%"><p>"<strong>${PARENT_NICK}</strong>" 同学,您曾发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${PARENT_COMMENT}</div><p>"<strong>${NICK}</strong>" 给您的回复如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击:<a style="text-decoration:none; color:#12addb" href="${POST_URL}">[回复的完整内容] </a>进行查看。欢迎再次光临<a style="text-decoration:none; color:#12addb" href="${SITE_URL}"> 『${SITE_NAME}』</a>!!!</p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

MAIL_SUBJECT_ADMIN

1
叮咚!『${SITE_NAME}』上有了新评论!

MAIL_TEMPLATE_ADMIN

1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px; color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您的<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> 『${SITE_NAME}』 </a>上有了新的评论 </p></div><div style="margin:40px auto;width:90%"><p><strong>"${NICK}"</strong> 发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p><a style="text-decoration:none; color:#12addb" href="${POST_URL}" target="_blank">[查看详情]</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

如果使用国际版leancloud,那么leancloud的定时任务要做一些调整。主要就是将官方的介绍时间调整成北京时区的时间。

image-20200306133741358

1
2
# 北京时间每天早8点检查过去24小时内漏发的通知邮件一并补发
0 0 0 * * ?
1
2
# 每天早0点到晚23点每隔30分钟访问云引擎
0 0/30 0-23 * * ?

4. 整合多个评论面板

编辑 /themes/next/layout/_third-party/comments/valine.swig,修改如下:

1
2
3
	new Valine({
- el: '#comments' ,
+ el: '#comments-valine' ,

编辑 themes/next/layout/_partials/comments.swig,修改如下:

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
  {% elseif theme.gitment.enable %}
<div class="comments" id="comments">
{% if theme.gitment.lazy %}
<div onclick="showGitment()" id="gitment-display-button">{{ __('gitmentbutton') }}</div>
<div id="gitment-container" style="display:none"></div>
{% else %}
<div id="gitment-container"></div>
{% endif %}
</div>


+ {% elseif theme.gitalk.enable and theme.valine.enable %}
+ <div class="comments" id="comments">
+ <div class="tablink-li">
+ <button class="tablink" onclick="openPage('tabs-gitalk',this)" id="defaultOpen">Gitalk</button>
+ <button class="tablink" onclick="openPage('tabs-valine',this)">Valine</button>
+ </div>
+ <div class="tabcontent-li">
+ <div id="tabs-gitalk" class="tabcontent">
+ <div id="gitalk-container"></div>
+ </div>
+ <div id="tabs-valine" class="tabcontent">
+ <div id="comments-valine"></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ function openPage(pageName, elmnt) {
+ var i, tabcontent;
+ tabcontent = document.getElementsByClassName("tabcontent");
+ for (i = 0; i < tabcontent.length; i++) {
+ tabcontent[i].style.display = "none";
+ }
+ tablinks = document.getElementsByClassName("tablink");
+ for (i = 0; i < tablinks.length; i++) {
+ tablinks[i].classList.remove("currentTabcontent");
+ }
+ document.getElementById(pageName).style.display = "block";
+ elmnt.classList.add("currentTabcontent");
+ }
+ document.getElementById("defaultOpen").click();;
+ </script>


- {% elseif theme.valine.appid and theme.valine.appkey %}
- <div class="comments" id="comments"></div>

+ {% elseif theme.valine.enable %}
+ <div class="comments" id="comments">
+ <div id="comments-valine"></div>
+ </div>

{% elseif theme.gitalk.enable %}
<div class="comments" id="comments">
<div id="gitalk-container"></div>
</div>

{% elseif theme.vssue.enable %}
<div class="comments" id="comments">
<div id="vssue"></div>
</div>

{% endif %}

{% endif %}

创建 themes/next/source/css/_custom/comments.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
/**
* 评论区样式
*/
.main-inner .comments {
// margin: 60px 0 20px 0;

// 去掉链接下的下划线
a {
border-bottom: none;
}

.highlight pre {
color: #24292e;
}

// 防止代码区边缘黑线
.highlight,
pre {
background: unset;
}

.highlight ::selection {
background: #2593a6;
color: #24292e;
}

.tablink-li {
margin-bottom: 30px;
}
.tabcontent-li {
border-top: solid 1px;
}
.tablink {
float: left;
border: none;
outline: 0;
cursor: pointer;
width: 60px;
color: #ddd;
background-color: #60676d;
}
.tablink:hover {
background-color: #222;
}
.tabcontent {
display: none;
}
.currentTabcontent {
background-color: #222;
}
.valine {
.vwrap {
.textarea-wrapper .comment_trigger {
background-color: #f6f6f6;
}
.textarea-wrapper textarea {
background-color: #f6f6f6;
}
.auth-section .input-wrapper input {
background-color: #f6f6f6;
}
.auth-section {
background-color: #f6f6f6;
}
.auth-section .post-action button {
background-color: #333;
}
}
}
}

✉️ 由于整合vssue的过程中发现单独使用没问题,但是和其他评论面板在一起发生回调地址不正确的问题,于是这里暂且只整合了Gitalk和Valine,如果有小伙伴找到了解决方案,欢迎联系本人,鲜花奉上!🌹

二十四、 github和coding双线路部署hexo

1. 配置

这里讲的是hexo一次部署能够实现github和coding两个远程仓库自动同步,你只要打开全局配置文件 myblog/_config.yml,搜索关键字 deploy,根据自己远程仓库地址做以下修改:

1
2
3
4
5
6
deploy:
type: git
repository:
github: git@github.com:qcmoke/qcmoke.github.io.git
coding: git@git.coding.net:qcmoke/qcmoke.coding.me.git
branch: master

2. 部署

和原来的单部署执行的命令一样:

1
2
$ hexo g
$ hexo d

🙆‍♂ 双线路部署hexo完成。

3. 额外补充

其实完成以上步骤就能实现简单版的双线路部署hexo了,但有两个问题:

(1)不同平台上的hexo博客需要不同的域名访问

(2)双线部署的的情况下,gittalk由于是通过域名来调用github OAuth Apps的api的,但是github和coding免费提供的是两个不同的域名,所以会导致api调用错乱而报错的问题。

我们希望用同一个域名就能同时访问github pages和coding pages,即所谓的负载均衡思想,而且还要解决gitalk api调用错乱的问题。

解决以上问题的前提是有一个自己的域名。至于怎么获取域名,我就不废话了 啊,百度吧朋友 😅 ~!这里就假设你已经有了自己的域名,然后按照下面的步骤一步一步完成即可。

3.1 解析域名CNAME记录

这里以qcmoke.site域名为例,将域名CNAME记录分别解析到你yourname.github.io和yourname.coding.me上。如下图:

1538252205493

如果你的dns解析托管服务商解析线路有“国内”线路,最好将 yourname.coding.me解析到国内线路。而 yourname.github.io解析到国外线路即可。如果没有的话,和我一样全选默认线路即可。

2.2 设置自定义域名

分别登录到github和coding后台,将你的域名填入并启用https即可。

(1)Github

1538252756980

💁‍♂提示:

github目前启用自定义域名的https服务大概需要等24小时才能生效。如果到时间了还未生效,并且"Enforce HTTPS"是灰色的不能选择或者没有这个选项,你可以清除设置中的custom domain 域名,再次填写保存即可解决,然后"Enforce HTTPS"选择打钩,一般就能启用https了。

💡 可选:你可以选择在仓库根目录中加入一个名为 CNAME的文件,里面填入你的域名,如 www.qcmoke.site,这和设置中填入自定义域名的效果是一样的)

(2)Coding

1538252857797

💁‍♂ 说明:

coding需要银牌以上会员才有权限加入自定义的域名。不过银牌会员是免费的,登录coding后找到会员设置后点击申请并完善个人信息后就能升级到银牌会员。

🙉 目前coding被腾讯大哥收购后,界面改了很多,请自行解决。

🌸 完成后你只要通过自定义的域名访问你的git page服务即可。

3.4 额外补充

💁‍♂如果你没有使用gitalk,可以直接跳过下面的内容。

上文中“加入评论面板”已经介绍如何创建“github OAuth Apps”,这里额外补充说明一下,和无自定义域名的情况不同 ,有自定义域名的情况只需要一个github OAuth Apps ,所以Homepage URL和Authorization callback URL都指向同一个地址路径,所以不同仓库下的gitalk实际调用的是同一个github OAuth Apps的api 。如果你之前已经为github博客和coding博客分别创建了两个github OAuth Apps,那么我建议你可以删除掉那些无用的github OAuth Apps了。然后重新创建一个github OAuth Apps,

1538254113055

注意:github OAuth Apps 上的Homepage URL和Authorization callback URL为你博客的新地址(自定义域名地址),如:https://www.qcmoke.site

修改 myblog/themes/next/_config.yml主题配置文件中的gitalk配置,配置完成如下图:

1538284914651

4. 关于coding广告

目前使用自定义域名,coding会强制在你打开博客时放入几秒钟的广告,在此吐槽一下💢。去除这个广告页面也不是没有办法,coding提供了一些办法,其中一种就是在你的博客首页加入他们家的链接。也就是“Hosted by Coding Pages”这几个字,虽然还是很讨厌,但是没办法,忍忍吧,毕竟要了人家的服务器啦。既然coding要求帮他们打广告,而我又用的是双线部署hexo博客到github和coding上的方案,故将计就计,那也顺便帮github打广告啦。具体做法如下:

myblog/themes/next/layout/_partials/footer.swig中找到如下代码块:

1
2
3
4
5
6
7
8
9
10
11
12
13
  {% if theme.post_wordcount.totalcount %}
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-area-chart"></i>
</span>
{% if theme.post_wordcount.item_text %}
<span class="post-meta-item-text">{{ __('post.totalcount') }}:</span>
{% endif %}
<span title="{{ __('post.totalcount') }}">{#
#}{{ totalcount(site, '0,0.0a') }}{#
#}</span>
{% endif %}
</div>

另起一行,添加如下代码:

1
2
3
4
<!-- Github Pages and coding pages ad -->
<span>Hosted by <a href="https://pages.github.com" style="font-weight: bold">Github Pages</a></span>
  and  
<span>Hosted by <a href="https://pages.coding.me" style="font-weight: bold">Coding Pages</a></span>

以上完成后还没结束,还要登录到coding后台设置选择“已放置 Hosted by Coding Pages”打钩。但你可能找不到这个设置页面,你需要切换coding主页回旧版再找pages服务设置,就能找到这个设置了,如下:

1538276541146

1538276615247

Hosted by Coding Pages 提交后需要审核,会在两个工作日内为你处理。处理成功后就不会有打开博客主页前的几秒钟广告推送了。

二十五、添加页面加载效果

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 pace_theme找到如下代码位置,将 pace设置为 truepace_theme可以根据列出了的样式进行选择:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Progress bar in the top during page loading.
pace: true
# Themes list:
#pace-theme-big-counter
#pace-theme-bounce
#pace-theme-barber-shop
#pace-theme-center-atom
#pace-theme-center-circle
#pace-theme-center-radar
#pace-theme-center-simple
#pace-theme-corner-indicator
#pace-theme-fill-left
#pace-theme-flash
#pace-theme-loading-bar
#pace-theme-mac-osx
#pace-theme-minimal
# For example
# pace_theme: pace-theme-center-simple
pace_theme: pace-theme-minimal

二十六、hexo博客静态资源压缩优化

用hexo生成静态文件时,默认生成的静态文件存在大量空白,而且css、js都未经压缩,这在一定程度上会影响页面的加载,所以在网上所搜有没有办法来优化这些问题?

答案肯定是有,当然大部分博客都提到了使用gulp来精简代码,而我今天所要跟大家介绍的是hexo-neat插件 。我为啥不选择gulp而使用hexo-neat呢?因为用gulp需要在每次生成静态文件后,即 hexo g后,都要另外执行 gulp命令才能压缩静态文件;而使用hexo-neat则无须另外执行其他命令即可自动完成压缩功能,即方便了使用习惯。

在站点的根目录下执行以下命令:

1
$ npm install hexo-neat --save

打开 myblog/_config.yml全局配置文件添加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#静态资源压缩优化
# hexo-neat
neat_enable: true # 启用neat

# 对html优化
neat_html:
enable: true
exclude:

# 对css优化
neat_css:
enable: true
exclude:
- '*.min.css'

# 对js优化
neat_js:
enable: true
mangle: true
output:
compress:
exclude:
- '*.min.js'

做好以上几步之后,重新生成博客的时候就会自动压缩所有的html、css、js。访问博客时能感到明显加快了。

二十七、置顶按钮显示百分比

打开 myblog/themes/next/_config.yml主题配置文件,搜索关键字 scrollpercent。 将其值设置为true。效果如下图:

1538356072444

二十八、自定义摘要图片和摘要描述

文章封面的意思就是:在博客首页的时候会显示文章的封面图片和摘要描述,进入这篇文章的详细页面后,将不显示这张图片和摘要描述。

如果想添加文章封面的话,需要添加字段属性:summary_imgsummary_img的值是图片的路径。

如果想要添加摘要描述的话,可以添加字段属性:summary_descriptionsummary_description 的值是描述的内容。

例如:

1
2
3
4
5
6
7
8
9
---
title: CSS 各种Hack手段
date: 2017-06-25 03:25:24
categories: 前端
tags: [CSS]
comments: false
summary_img: /images/css-hack-1.png
summary_description: 封面摘要描述,了解一下!
---

具体实现细节如下:
修改 myblog/themes/next/layout/_macro/post.swig 文件。
将代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 自定义摘要图片开始 -->
{% if post.summary_img %}
<div class="out-img-topic">
<img src={{ post.summary_img }} class="img-topic">
</div>
{% endif %}
<!-- 自定义摘要图片结束 -->
<!-- 自定义摘要描述开始 -->
{% if post.summary_description %}
<div class="post-button text-center">
<div>{{ post.summary_description }}</div>
</div>
{% endif %}
<!-- 自定义摘要描述结束 -->

添加到以下所示的位置

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
  {% if is_index %}
<!-- 自定义摘要图片开始 -->
{% if post.summary_img %}
<div class="out-img-topic">
<img src={{ post.summary_img }} class="img-topic">
</div>
{% endif %}
<!-- 自定义摘要图片结束 -->
<!-- 自定义摘要描述开始 -->
{% if post.summary_description %}
<div class="post-button text-center">
<div>{{ post.summary_description }}</div>
</div>
{% endif %}
<!-- 自定义摘要描述结束 -->
{% if post.description and theme.excerpt_description %}
{{ post.description }}
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% elif post.excerpt %}
{{ post.excerpt }}
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}{% if theme.scroll_to_more %}#{{ __('post.more') }}{% endif %}" rel="contents">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% elif theme.auto_excerpt.enable %}
{% set content = post.content | striptags %}
{{ content.substring(0, theme.auto_excerpt.length) }}
{% if content.length > theme.auto_excerpt.length %}...{% endif %}
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}{% if theme.scroll_to_more %}#{{ __('post.more') }}{% endif %}" rel="contents">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% else %}
{% if post.type === 'picture' %}
<a href="{{ url_for(post.path) }}">{{ post.content }}</a>
{% else %}
{{ post.content }}
{% endif %}
{% endif %}
{% else %}
{{ post.content }}
{% endif %}
</div>
{#####################}
{### END POST BODY ###}
{#####################}

这样的话,就可以使用 summary_img: imageurlsummary_description: description demo来设置文章封面和摘要描述了。

💡建议:

开启了文章封面和摘要描述的文章,我建议将 <!-- more --> 放在文章正文内容的开头。

为了适应不同大小的图片,摘要图片的样式需要做一下调整。在 myblog/themes/next/source/css/_custom/custom.styl中添加以下样式代码:

1
2
3
4
//缩略图指定宽度值显示。
img.img-topic {
width: 75%;
}

如果希望hexo默认description也和summary_description居中显示,同样修改 myblog/themes/next/layout/_macro/post.swig 文件。找到以下代码。

1
2
3
4
5
6
7
8
9
10
{% if post.description and theme.excerpt_description %}
{{ post.description }}
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% elif post.excerpt %}

将以上代码改成:

1
2
3
4
5
6
7
8
9
10
11
12
{% if post.description and theme.excerpt_description %}
<div class="post-button text-center">
<div>{{ post.description }}</div>
</div>
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% elif post.excerpt %}

二十九、添加在线联系功能

在这使用的是DaoVoice做在线联系功能。
首先到DaoVoice上注册一个账号,注册完成后会得到一个app_id,获取appid的步骤如下图所示:

1538456184961

打开myblog/themes/next/layout/_partials/head.swig文件找到如下代码:

1
{% include 'head/custom-head.swig' %}

另起一行添加如下代码(实际我就是添加到最后):

1
2
3
4
5
6
7
8
9
{% if theme.daovoice %}
<script>
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/0f81ff2f.js","daovoice")
daovoice('init', {
app_id: "{{theme.daovoice_app_id}}"
});
daovoice('update');
</script>
{% endif %}

打开 myblog/themes/next/_config.yml主题配置文件

1
2
3
# Online contact 
daovoice: true
daovoice_app_id: 33***da4 #这里输入前面获取的app_id

最后执行 hexo clean && hexo g && hexo s,打开博客就能看到效果了。如下图:

1538456671856

当然为了调整图标的位置,你可以登陆daovoice后台进行修改,如下图:

1538456771783

最后到右上角选择管理员,微信绑定,可以绑定你的微信号,关注公众号后打开小程序,在微信中登陆daovoice,就可以实时收发消息,有新的消息也会通过微信的小程序通知,设置页面如下:

1538456906088

三十、优化深色代码高亮背景

在主题配置文件修改代码高亮背景为深色背景后,当在博客文章上选择代码时,选择到的颜色也为深色,虽然和背景色还是有点点区别,但是不好区分。所以经过一番研究,才有了以下优化教程。

myblog/themes/next/source/css/_custom/custom.styl中添加以下样式代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//page code background-color
.code ::selection {
background: #2593a6;
color: #fff;
}
.code +mobile() {
background: #2593a6;
color: #fff;
}


//gitalk code background-color
.gt-container .gt-comment-content .highlight pre, .markdown-body pre{
background-color: #2d2d2d;
}
.gt-container .gt-comment-content .highlight ::selection {
background: #2593a6;
color: #fff;
}

以上代码优化了所以高亮代码区域,包括gitalk评论区的高亮代码。 这些样式代码是通过浏览器调试而得,如有其它样式的需求,可参考本示例在浏览器中调试。

三十一、修改文章底部带#号的标签

打开 myblog/themes/next/layout/_macro/post.swig文件,搜索 rel="tag">#,将 # 换成 <i class="fa fa-tag">,如下:

1
2
3
4
5
<div class="post-tags">
{% for tag in post.tags %}
<a href="{{ url_for(tag.path) }}" rel="tag"><i class="fa fa-tag"></i> {{ tag.name }}</a>
{% endfor %}
</div>

三十二、文章末尾添加“本文结束”标记

在路径 myblog/themes/next/layout/_macro中新建 passage-end-tag.swig文件,并复制以下代码到 passage-end-tag.swig 中:

1
2
3
4
5
6
7
8
9
10
11
<div>
{% if not is_index %}
<br />
<br />
<div style="text-align:center;color: #ccc;font-size:14px;">----------- 本文结束 -----------</div>
<br />
<br />
<br />
<br />
{% endif %}
</div>

打开myblog/themes/next/layout/_macro/下的post.swig文件,找到如下代码块:

1
2
3
{#####################}
{### END POST BODY ###}
{#####################}

在以上代码块的上面另起一行添加如下代码:

1
2
3
4
5
<div>
{% if not is_index %}
{% include 'passage-end-tag.swig' %}
{% endif %}
</div>

然后打开主题配置文件myblog/themes/next/_config.yml,在末尾添加:

1
2
3
# 文章末尾添加“本文结束”标记
passage_end_tag:
enabled: true

三十三、修改文章内链接文本样式

myblog/themes/next/source/css/_custom/custom.styl中添加以下样式代码:

1
2
3
4
5
6
7
8
9
10
11
//文章内链接文本样式
.post-body p a{
color: #0593d3;
border-bottom: none;
border-bottom: 1px solid #0593d3;
&:hover {
color: #fc6423;
border-bottom: none;
border-bottom: 1px solid #fc6423;
}
}

可以根据自己的喜好使用浏览器调试得到相应的样式。

三十四、添加404页面

每个站长都应该有一份社会责任心,力所能及的时候可以让你的404页面加入腾讯404公益平台:https://www.qq.com/404/ 。早期的腾讯404JS。有2个问题,不支持https,homepage定制能力不稳定;比较令人诟病,如今的腾讯404已经支持https。可以直接使用。
myblog/myblog/source目录下新建名称为 404.html的文件,编辑此文件,根据复制粘贴以下代码并根据自己的情况做必要修改。具体修改细节,在以下代码有说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
layout: false
title: "404"
---
<!DOCTYPE html>
<html>
<head>
<!-- 浏览器标签图标,此处需要在myblog/themes/next/source/images中加入favicon.jpg图片 -->
<link rel="shortcut icon" href="images/favicon.jpg" />
</head>
<body>
<!-- 以下" https://www.qcmoke.site/ "改成自己的主页地址 -->
<script type="text/javascript" src="//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js" charset="utf-8" homePageUrl="https://www.qcmoke.site/" homePageName="回到我的主页"></script>
</body>
</html>

部署服务器后,访问不存在的资源时即可打开公益404页面。

注意:不能通过本地localhost访问,要部署后通过自己域名来访问。

三十五、Gemini布局返回顶部按钮适配移动端

由于自己不才,为了解决这个问题,不知花了多少时间和精力。在这个折腾的过程中,有上过百度和谷歌搜了好多的教程但却无功而返;后来又尝试通过浏览器调试来解决这个问题,也同样以失败而告终。在几近绝望时,网友分享了一篇博客文章《在移动设备下启用NexT主题的目录页面和回到顶部按钮》,经参考并做修改后才有了以下简陋的教程。

  • 教程开始:

编辑 themes/next/source/css/_common/components目录下的 back-to-top.stylback-to-top-sidebar.styl文件。用 /* */注释掉以下代码。(注意:两个文件都要注释掉)

1
2
3
4
5
6
7
8
+tablet() {
fixbutton() if hexo-config('sidebar.onmobile');
hide() if not hexo-config('sidebar.onmobile');
}
+mobile() {
fixbutton() if hexo-config('sidebar.onmobile');
hide() if not hexo-config('sidebar.onmobile');
}

注释后如下:

1
2
3
4
5
6
7
8
9
10
/*
+tablet() {
fixbutton() if hexo-config('sidebar.onmobile');
hide() if not hexo-config('sidebar.onmobile');
}
+mobile() {
fixbutton() if hexo-config('sidebar.onmobile');
hide() if not hexo-config('sidebar.onmobile');
}
*/

三十六、去除侧栏目录自动生成的序数

编辑 myblog/themes/next/_config.yml主题配置文件,搜索关键字 toc找到如下代码,number默认是 true,将 number设置为 false,如下:

1
2
3
4
5
6
7
8
toc:
enable: true

# Automatically add list number to toc.
number: false

# If true, all words will placed on next lines if header width longer then sidebar width.
wrap: false

三十七、添加最近文章栏目

编辑 myblog/themes/next/layout/_macro/sidebar.swig 。找到 theme.social板块代码,在该板块最后的 endif后隔一行添加如下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{# recent posts #}
{% if theme.recent_posts %}
<div class="links-of-blogroll motion-element {{ "links-of-blogroll-" + theme.recent_posts_layout }}">
<div class="links-of-blogroll-title">
<!-- modify icon to fire by szw -->
<i class="fa fa-history fa-{{ theme.recent_posts_icon | lower }}" aria-hidden="true"></i>
{{ theme.recent_posts_title }}
</div>
<ul class="links-of-blogroll-list">
{% set posts = site.posts.sort('-date') %}
{% for post in posts.slice('0', '5') %}
<li class="recent_posts_li">
<a href="{{ url_for(post.path) }}" title="{{ post.title }}" target="_blank">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}

再编辑 myblog/themes/next/source/css/_common/components/sidebar/sidebar-blogroll.styl

在文件最后添加如下样式代码

1
2
3
4
5
6
7
8
li.recent_posts_li {
text-align: left;
display: block;
word-break: keep-all;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

编辑主题配置文件 myblog/themes/next/_config.yml,添加如下代码:

1
2
3
recent_posts_title: 近期文章
recent_posts_layout: block
recent_posts: true

三十八、魔改Muset布局

由于个人喜好,和为适配移动端,本博客从这里开始将修改next布局为Muse。并在Muse的基础上做了比较大的样式调整,形成了目前博客现状的基本布局和样式。其中包括整体骨架布局、菜单栏、首页文章缩略卡片、文章页宽、移动端适配、字体大小等等众多样式的调整。

修改 themes/next/_config.yml启用 Muset:

1
2
3
4
5
# Schemes
scheme: Muse
#scheme: Mist
#scheme: Pisces
#scheme: Gemini

然后编辑 themes/next/source/css/_custom/custom.styl添加自定义样式:

需要特别注意:这里的custom.styl样式内容是修改后的第一版,一切的博客样式更新都不会在这里另做修改。如果想参考最新版,可以移步到本文倒数第二大点,查看最新版本的custom.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
//page code background-color
.code ::selection {
background: #2593a6;
color: #fff;
}
.code +mobile() {
background: #2593a6;
color: #fff;
}


//gitalk code background-color
.gt-container .gt-comment-content .highlight pre, .markdown-body pre{
background-color: #2d2d2d;
}
.gt-container .gt-comment-content .highlight ::selection {
background: #2593a6;
color: #fff;
}


//缩略图指定宽度值显示。
img.img-topic {
width: 55%;
}


// 文章内链接文本样式
.post-body p a{
color: #0593d3;
border-bottom: none;
border-bottom: 1px solid #0593d3;
&:hover {
color: #fc6423;
border-bottom: none;
border-bottom: 1px solid #fc6423;
}
}


//归档页位置调整
.posts-collapse .post-header::before {
left: -3px;
}
.posts-collapse .collection-title {
margin: 50px 0 5px 0;
}



//页面顶部样式
.header {
background-image: linear-gradient(90deg,#222325,#3b3c3f,#222325);
}
.brand {
background: none;
}
.btn-bar {
background: #f9f9f9;
}
.container .header-inner {
padding-top: 0px;
padding-bottom: 0px;
width: 100%;
}
.site-title {
font-size: 29px;
font-weight: bold;
letter-spacing: 0px;
}
.site-subtitle {
margin-top: 7px;
color: #999;
margin-bottom: 5px;
font-size: 10px;
font-weight: 700;
}


//页面顶部菜单样式
.menu {
text-align: center;
margin-top: 0px;
margin-bottom: 0px;
padding: 1px;
background-color: rgba(255, 255, 255, 0.75);
box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.15);
}
// 菜单超链接字体大小和颜色
.menu .menu-item a {
padding-left: 20px;
padding-right: 20px;
font-weight: 600;
font-size: 13px;
color: #333
}
.menu .menu-item a:hover {
font-weight: bold;
color: black;
}


//文章样式
//文章宽度
.main-inner {
margin: 0 auto;
width: 960px;
}
//文章列表宽度
section#posts {
width: 78%;
margin: 0 auto;
}

// 文章
.post {
margin-bottom: 10px;
padding: 45px 28px 36px 28px;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5);
background-color: rgb(255, 255, 255);
}
// 文章标题字体
.posts-expand .post-title {
font-size: 20px;
font-weight: 700;
}
// 文章元数据(meta)留白更改
.posts-expand .post-meta {
margin: 10px 0px 20px 0px;
}
//缩略图边缘样式
section#posts .post-body img {
padding: 0px;
border: none;
}
// 文章的描述description
.posts-expand .post-meta .post-description {
font-style: italic;
font-size: 14px;
margin-top: 30px;
margin-bottom: 0px;
color: #666;
}
// 去除在页面文章之间的分割线
.posts-expand .post-eof {
margin: 0px;
background-color: rgba(255, 255, 255, 0);
}
// 去除页面底部页码上面的横线
.pagination {
border: none;
margin: 0px;
}

// 文章底部留白更改
.post-widgets {
padding-top: 0px;
}
.post-nav {
margin-top: 30px;
}

.category-all-page .category-list {
margin: 0;
padding: 0;
list-style: none;
margin-left: 44%;
}
a.category-list-link {
font-size: 20px;
font-weight: bold;
}

.posts-collapse {
margin-top: 50px;
}
.posts-collapse .post {
margin: 0 0;
margin-top: 0;
padding: 2px;
box-shadow: none;
}
.posts-collapse .post-header {
position: relative;
transition-duration: .2s;
transition-timing-function: ease-in-out;
transition-delay: 0s;
transition-property: border;
border-bottom: 1px dashed #ccc;
}

.pagination {
margin-top: 50px;
}

//最近文章链接样式
li.recent_posts_li {
text-align: center;
}


@media (min-width: 1600px){
.container .main-inner {
width: 1080px;
}
section#posts {
width: 83%;
margin: 0 auto;
}
.menu .menu-item a {
font-size: 15px;
}
.highlight, pre{
font-size: 14px;
}
}

@media (max-width: 767px)
{
.site-overview {
overflow-y: auto;
overflow-x: hidden;
}
.header {
background: black;
}
.site-subtitle {
margin-top: 11px;
display: block;
padding-bottom: 2px;
}
.posts-expand {
margin: 0;
}
img.img-topic {
width: 60%;
}
.main-inner {
margin: 0 auto;
width: inherit;
}
.posts-expand {
padding-top: 0;
}
.post {
padding: 45px 12px 36px 12px;
}
//移动端文章列表宽度
section#posts {
width: 85%;
margin: 0 auto;
}
.sidebar-toggle {
right: 20px;
opacity: unset;
bottom: 58px;
width: 20px;
height: 20px;
}
.sidebar-toggle-line {
height: 3px;
}
.back-to-top {
right: 20px;
}
//移动端footer字体变小,防止换行
.footer-inner {
font-size: 11px;
}
}

@media (max-width: 960px) {
.posts-expand {
margin: 0;
}
.back-to-top {
right: 20px;
}
.main-inner {
margin: 0 auto;
width: inherit;
}
//移动端文章列表宽度
section#posts {
width: 85%;
margin: 0 auto;
}
}

经过上面一番折腾后最终得到如下博客主题布局效果。

image-20200303022203833

三十九、插入音乐和视频

1. html原生方式

1.1 音乐面板

在markdown文章里使用 HTML 的标签引入,写法如下

1
<audio src="https://什么什么什么.mp3" style="max-height :100%; max-width: 100%; display: block; margin-left: auto; margin-right: auto;" controls="controls" loop="loop" preload="meta">Your browser does not support the audio tag.</audio>

1.2 视频面板

在markdown文章里使用 HTML 的标签引入,写法如下

1
<video poster="https://封面图.jpg" src="https://什么什么什么.mp4" style="max-height :100%; max-width: 100%; display: block; margin-left: auto; margin-right: auto;" controls="controls" loop="loop" preload="meta">Your browser does not support the video tag.</video>

2. 第三方插件方式

2.1 音乐面板插件

此前有尝试过使用网易云音乐外链的方式给博客加入音乐面板,但使用的过程中发现有一些音乐因为版权原因播放不了,还有就是不完全支持 https,导致小绿锁不见了。要解决这些缺点,就需要另辟蹊径转而安装第三方音乐面板插件了,hexo-tag-aplayer是一个音乐面板插件,功能很强大,相比于原生html的视频面板而言,可玩性更丰富,比如可以有歌词,歌单列表等等。废话不多说,直接上教程。

安装音乐面板插件

1
$ npm install hexo-tag-aplayer --save

单首歌曲的形式

通过模板语法在markdown文章里引入,写法如下:

1
{% aplayer "歌曲名" "歌手名" "https://什么什么什么.mp3" "https://封面图.jpg" "lrc:https://歌词.lrc" %}

歌单的形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{% aplayerlist %}
{
"autoplay": false,
"showlrc": 3,
"mutex": true,
"music": [
{
"title": "歌曲名",
"author": "歌手名",
"url": "https://什么什么什么.mp3",
"pic": "https://封面图.jpg",
"lrc": "https://歌词.lrc"
},
{
"title": "歌曲名",
"author": "歌手名",
"url": "https://什么什么什么.mp3",
"pic": "https://封面图.jpg",
"lrc": "https://歌词.lrc"
}
]
}
{% endaplayerlist %}

详细参数见 README 和这插件的“母亲” Aplayer 的官方文档

关于 lrc 歌词,可以参考知乎的这篇文章https://www.zhihu.com/question/27638171下载网易云音乐的歌词,如果那歌词有错误(比如字母大小写和标点符号乱加)或者时间完全对不上,你可以一句一句自己查看修改……

2.2 视频面板

hexo-tag-dplayer插件功能相比于原生html视频标签会更加强大,比如可以使用弹幕,非常建议食用。

安装插件

1
$ npm install hexo-tag-dplayer --save

通过模板语法在markdown文章里引入,写法如下:

1
{% dplayer "url=https://什么什么什么.mp4" "pic=https://封面图.jpg" "api=https://api.prprpr.me/dplayer/" "id=" "loop=false" %}

如果要使用弹幕,必须有 apiid两项,并且若使用的是官方的 api 地址(即上面的),id 的值不能与这个列表的值一样。id 的值自己随便取,但建议使用视频的哈希值,可参考http://tool.oschina.net/encrypt?type=2。

目前发现官方api不能使用,可以寻求其他免费的弹幕服务器。也可自行搭建,可参考:

📚 https://alone88.cn/archives/484.html

📚 https://dandoc.u2sb.top/

关于这个插件的更多内容可以去 README 和这插件的“母亲” Dplayer 的官方文档看看。

3. 音乐面板综合案例

新建一个hexo markdown文章文件

1
$ hexo n music

在新建的music.md文件里加入如下内容:

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
---
title: 我的音乐页面
date: 2020-03-02 22:21:39
---
<!-- more -->

<audio src="https://source.qcmoke.site/music/houhuiwuqi.mp3" style="max-height :100%; max-width: 100%; display: block; margin-left: auto; margin-right: auto;" controls="controls" loop="loop" preload="meta">Your browser does not support the audio tag.</audio>


{% aplayer "歌曲名" "歌手名" "https://source.qcmoke.site/music/houhuiwuqi.mp3" "https://source.qcmoke.site/music/houhuiwuqi.jpg" "lrc:https://source.qcmoke.site/music/houhuiwuqi.lrc" %}



{% aplayerlist %}
{
"autoplay": false,
"showlrc": 3,
"mutex": true,
"music": [
{
"title": "后会无期",
"author": "G.E.M. 邓紫棋",
"url": "https://source.qcmoke.site/music/houhuiwuqi.mp3",
"pic": "https://source.qcmoke.site/music/houhuiwuqi.jpg",
"lrc": "https://source.qcmoke.site/music/houhuiwuqi.lrc"
},
{
"title": "王牌冤家",
"author": "李荣浩",
"url": "https://source.qcmoke.site/music/wangpaiyuanjia.mp3",
"pic": "https://source.qcmoke.site/music/wangpaiyuanjia.jpg",
"lrc": "https://source.qcmoke.site/music/wangpaiyuanjia.lrc"
},
{
"title": "if you",
"author": "Bigbang",
"url": "https://source.qcmoke.site/music/ifyou.mp3",
"pic": "https://source.qcmoke.site/music/ifyou.jpg",
"lrc": "https://source.qcmoke.site/music/ifyou.lrc"
}
]
}
{% endaplayerlist %}

效果

image-20200302224536365

4. 视频面板综合案例

新建一个hexo markdown文章文件

1
$ hexo n video

在新建的video.md文件里加入如下内容:

1
2
3
4
5
6
7
8
9
10
---
title: 我的视频页面
date: 2020-03-02 22:21:39
---
<!-- more -->

<video poster="http://localhost:4000/images/logo.jpg" src="https://source.qcmoke.site/video/VID_20190503_143115.mp4" style="max-height :100%; max-width: 100%; display: block; margin-left: auto; margin-right: auto;" controls="controls" loop="loop" preload="meta">Your browser does not support the video tag.</video>


{% dplayer "url=https://source.qcmoke.site/video/VID_20190503_143115.mp4" "http://localhost:4000/images/logo.jpg" "api=https://api.prprpr.me/dplayer/" "id=" "loop=false" %}

效果:

image-20200302233729240

四十、更改上下篇的顺序

默认next文章下面的"上一篇,下一篇"是旧发布的文章在上篇里的,但是如果希望新的发布文章在上篇的话就要做修改或者配置了,最新版本的next似乎已经可以直接在主题配置文件里设置了,但我这里使用的是旧版本的next5.1.4,所以需要深入源码进行修改,可以参考下面的方案。

编辑 blog/themes/next/layout/_macro/post.swig 然后做以下修改:

找到以下代码块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% if not is_index and (post.prev or post.next) %}
<div class="post-nav">
<div class="post-nav-next post-nav-item">
{% if post.next %}
<a href="{{ url_for(post.next.path) }}" rel="next" title="{{ post.next.title }}">
<i class="fa fa-chevron-left"></i> {{ post.next.title }}
</a>
{% endif %}
</div>

<span class="post-nav-divider"></span>

<div class="post-nav-prev post-nav-item">
{% if post.prev %}
<a href="{{ url_for(post.prev.path) }}" rel="prev" title="{{ post.prev.title }}">
{{ post.prev.title }} <i class="fa fa-chevron-right"></i>
</a>
{% endif %}
</div>
</div>
{% endif %}

将以上代码修改成以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% if not is_index and (post.prev or post.next) %}
<div class="post-nav">
<div class="post-nav-next post-nav-item">
{% if post.prev %}
<a href="{{ url_for(post.prev.path) }}" rel="prev" title="{{ post.prev.title }}">
<i class="fa fa-chevron-left"></i> {{ post.prev.title }}
</a>
{% endif %}
</div>

<span class="post-nav-divider"></span>

<div class="post-nav-prev post-nav-item">
{% if post.next %}
<a href="{{ url_for(post.next.path) }}" rel="next" title="{{ post.next.title }}">
{{ post.next.title }} <i class="fa fa-chevron-right"></i>
</a>
{% endif %}
</div>
</div>
{% endif %}

四十一、添加看板娘

目的是给博客页面添加小萌宠,给博客添加一点趣味性,下面就介绍使用live2d插件来实现这个功能。

(1)下载并安装插件

1
$ npm install --save hexo-helper-live2d

(2)下载并安装萌宠模型

1
$ npm install 模型名称

官方提供了以下模型名称:

  • live2d-widget-model-chitose
  • live2d-widget-model-epsilon2_1
  • live2d-widget-model-gf
  • live2d-widget-model-haru/01 (use npm install --save live2d-widget-model-haru)
  • live2d-widget-model-haru/02 (use npm install --save live2d-widget-model-haru)
  • live2d-widget-model-haruto
  • live2d-widget-model-hibiki
  • live2d-widget-model-hijiki
  • live2d-widget-model-izumi
  • live2d-widget-model-koharu
  • live2d-widget-model-miku
  • live2d-widget-model-ni-j
  • live2d-widget-model-nico
  • live2d-widget-model-nietzsche
  • live2d-widget-model-nipsilon
  • live2d-widget-model-nito
  • live2d-widget-model-shizuku
  • live2d-widget-model-tororo
  • live2d-widget-model-tsumiki
  • live2d-widget-model-unitychan
  • live2d-widget-model-wanko
  • live2d-widget-model-z16

你可以查看demo演示后再决定做选择。

(3)编辑Hexo主配置文件 myblog/_config.yml,添加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
## Live2D
## https://github.com/EYHN/hexo-helper-live2d
live2d:
enable: true
# enable: false
scriptFrom: local # 默认
pluginRootPath: live2dw/ # 插件在站点上的根目录(相对路径)
pluginJsPath: lib/ # 脚本文件相对与插件根目录路径
pluginModelPath: assets/ # 模型文件相对与插件根目录路径
# scriptFrom: jsdelivr # jsdelivr CDN
# scriptFrom: unpkg # unpkg CDN
# scriptFrom: https://cdn.jsdelivr.net/npm/live2d-widget@3.x/lib/L2Dwidget.min.js # 你的自定义 url
tagMode: false # 标签模式, 是否仅替换 live2d tag标签而非插入到所有页面中
debug: false # 调试, 是否在控制台输出日志
model:
use: live2d-widget-model-haruto # npm-module package name
# use: wanko # 博客根目录/live2d_models/ 下的目录名
# use: ./wives/wanko # 相对于博客根目录的路径
# use: https://cdn.jsdelivr.net/npm/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json # 你的自定义 url
display: # 模型位置,根据不同的模型自行调整
position: left
width: 100
height: 150
mobile: # 是否适用于移动端
show: false

四十二、图片懒加载

懒加载,即在需要的时候才加载图片,而不是一次性加载完整个页面的图片,使用lazyload插件实现懒加载可以有效提高博客的访问速度。

在Hexo博客目录下,执行以下命令:

1
$ npm install hexo-lazyload-image --save

编辑Hexo主配置文件 myblog/_config.yml,添加如下配置:

1
2
3
4
lazyload:
enable: true
onlypost: false
#loadingImg: ../images/loading-post.gif

参数:

enable:是否开启图片做懒加载功能

onlypost:是否仅文章中的图片做懒加载,如果为 false,则主题中的其他图片,也会做懒加载,如头像,logo 等任何图片。

loadingImg:图片未加载时的代替图,不填写使用默认加载图片,如果需要自定义,添填入 loading 图片地址,如果是本地图片,不要忘记把图片添加到你的主题目录下。 Next 主题需将图片放到 themes/next/source/images 目录下,然后引用时:loadingImg: ../images/xxx.gif

四十三、指定文章禁用侧栏目录

对于Muse布局,如果页面含有多级标题,那么默认是会自动展开侧栏抽屉目录的,但实际的使用中,我们不希望比如关于页面,友情页面等等自动展开目录,那么就需要对next做一定的修改来实现这个需求。

找到了 themes/next/layout/_marcro/sidebar.swig中找到下一列信息。

1
{% set display_toc = is_post and theme.toc.enable or is_page and theme.toc.enable %}

将其修改为:

1
{% set display_toc = is_post and theme.toc.enable and !page.no_toc or is_page and theme.toc.enable and !page.no_toc %}

如果需要指定某篇文章禁用侧栏目录,只需要在该文章Front-Matter部分添加一个 no_toc: true即可。

如下:

1
2
3
4
5
6
---
title: 友情链接
date: 2020-02-18 22:32:49
no_toc: true
comments: true
---

方案来源:http://master.hellosenlin.netlify.com/posts/24546/

四十四、优化图片点击放大功能

默认fancybox开启后,所有文字的图片都会强制被加入到了fancybox弹出框,并且fancybox会和图片链接冲突,如果想让某些图片禁用fancybox的话可以对next做一些修改来实现这个小功能。

修改 themes/next/source/js/src/utils.js文件:

1
2
3
4
5
6
7
8
9
  wrapImageWithFancyBox: function () {
$('.content img')
.not('[hidden]')
.not('.group-picture img, .post-gallery img')
.each(function () {
var $image = $(this);
+ if ($image.hasClass('nofancybox')) return;
var imageTitle = $image.attr('title');
var $imageWrapLink = $image.parent('a');

然后在使用的时候,给不需要 fancybox 的标签中添加class属性 class="nofancybox",如果 class 属性中已经有其它内容,也可以以空格并列,比如下面:

1
<img class="logoimg nofancybox" src="https://www.qcmoke.site/images/logo.jpg">

四十五、添加代码块全选复制功能

下载第三方插件:clipboard.js, 或者直接下载 (右键另存为)。保存 clipboard.min.js文件到 theme/next/source/js/src 下。然后在 theme/next/source/js/src 目录下,创建 clipboard-use.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
/*页面载入完成后,创建复制按钮*/
!(function(e, t, a) {
var initCopyCode = function() {
var copyHtml ='<button class="btn-copy" data-clipboard-snippet=""><i class="fa fa-clipboard"></i></button>';
$(".highlight .code pre").before(copyHtml);
var clipboard = new ClipboardJS(".btn-copy", {
target: function(trigger) {
return trigger.nextElementSibling;
}
});
clipboard.on("success", function(e) {
var button = e.trigger;
var iElement = button.querySelector("i");
iElement.className = "fa fa-check";
button.onmouseleave = function(ev) {
e.clearSelection();
setTimeout(function() {
iElement.className = "fa fa-clipboard";
}, 1000);
};
});
};
initCopyCode();
})(window, document);

theme/next/source/css/_custom/custom.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
//代码块复制按钮
.highlight{
//方便copy代码按钮(btn-copy)的定位
position: relative;
}
.btn-copy {
display: inline-block;
cursor: pointer;
background-color: #eee;
background-image: linear-gradient(#fcfcfc,#eee);
border: 1px solid #d5d5d5;
border-radius: 3px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-appearance: none;
font-size: 13px;
font-weight: 700;
line-height: 20px;
color: #333;
-webkit-transition: opacity .3s ease-in-out;
-o-transition: opacity .3s ease-in-out;
transition: opacity .3s ease-in-out;
padding: 2px 6px;
//固定在代码块的右上角,父relative+子fixed==>父relative+子absolute,这里可以根据自己的情况做调整fixed或者absolute
//父relative+子fixed
position: fixed;
margin-top: 2px;
//父relative+子absolute
//position: absolute;
//top: 5px;
right: 5px;
opacity: 0;
}
.btn-copy span {
margin-left: 5px;
}
.highlight:hover .btn-copy{
opacity: 1;
}

themes/next/layout/_layout.swig 文件中引用(</body>)之前添加:

1
2
3
<!-- 添加代码块全选复制功能 -->
<script type="text/javascript" src="/js/src/clipboard.min.js"></script>
<script type="text/javascript" src="/js/src/clipboard-use.js"></script>

四十六、添加mac代码面板

创建 themes/next/scripts/codeblock.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var attributes = [
'autocomplete="off"',
'autocorrect="off"',
'autocapitalize="off"',
'spellcheck="false"',
'contenteditable="true"'
]
var attributesStr = attributes.join(' ')
hexo.extend.filter.register('after_post_render', function (data) {
var patt = /<figure class="highlight(\s?)([a-zA-Z]*)">.*?<\/figure>/;
while (patt.test(data.content)) {
data.content = data.content.replace(patt, function () {
var language = RegExp.$2 || 'plain'
var lastMatch = RegExp.lastMatch
lastMatch = lastMatch.replace('<figure class="highlight', '<figure class="iseeu highlight')
return '<div class="highlight-wrap"' + attributesStr + 'data-rel="' + language.toUpperCase() + '">' + lastMatch + '</div>'
})
}
return data
})

创建 themes/next/source/css/_custom/macPanel.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
// mac Panel效果代码块相关
.highlight-wrap[data-rel] {
position: relative;
overflow: hidden;
border-radius: 5px;
box-shadow: 0 10px 30px 0px rgba(0, 0, 0, 0.4);
margin: 35px 0;
margin-top: 10px;
margin-bottom: 25px;

&::before {
color: white;
content: attr(data-rel);
height: 38px;
line-height: 38px;
background: #21252b;
color: #fff;
font-size: 16px;
position: absolute;
top: 0;
left: 0;
width: 100%;
//font-family: 'Source Sans Pro', sans-serif;
font-weight: bold;
padding: 0px 80px;
text-indent: 15px;
float: left;
}
&::after {
content: ' ';
position: absolute;
-webkit-border-radius: 50%;
border-radius: 50%;
background: #fc625d;
width: 12px;
height: 12px;
top: 0;
left: 20px;
margin-top: 13px;
-webkit-box-shadow: 20px 0px #fdbc40, 40px 0px #35cd4b;
box-shadow: 20px 0px #fdbc40, 40px 0px #35cd4b;
z-index: 3;
}
}

.highlight, pre {
margin-bottom: unset;
margin-top: 35px;
}

修改 themes/next/source/css/_custom/custom.styl,在最后追加如下:

1
@require "macPanel"

四十七、mac代码面板整合全选复制按钮

为了实现这个整合,我可真是花了不少时间,问了很多其他博主,但都无果,后来发现最新版的next其实已经实现了这个整合的功能,但是很遗憾的是我博客的next还是比较旧的版本,没办法直接配置实现。索性我直接去下载了最新版的next进行研究,通过一番较劲后,我终于做出来了,下面奉上教程:

1. 调整说明

如果是按照上文步骤一步一步实现下来的,那么为了实现整合,还得做以下调整。如果没有经过以上步骤,可以直接跳到第2点。

由于mac面板直接整合了代码全选复制按钮,所以可以把下面这些文件删除掉

themes/next/source/js/src/clipboard-use.js

themes/next/source/css/_custom/macPanel.styl

themes/next/scripts/codeblock.js

此外还要做一些修改,删除掉以下文件的相关代码:

文件1:themes/next/layout/_layout.swig

1
2
3
<!-- 添加代码块全选复制功能 -->
<script type="text/javascript" src="/js/src/clipboard.min.js"></script>
<script type="text/javascript" src="/js/src/clipboard-use.js"></script>

文件2:themes/next/source/css/_custom/custom.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
//代码块复制按钮
.highlight{
//方便copy代码按钮(btn-copy)的定位
position: relative;
}
.btn-copy {
display: inline-block;
cursor: pointer;
background-color: #eee;
background-image: linear-gradient(#fcfcfc,#eee);
border: 1px solid #d5d5d5;
border-radius: 3px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-appearance: none;
font-size: 13px;
font-weight: 700;
line-height: 20px;
color: #333;
-webkit-transition: opacity .3s ease-in-out;
-o-transition: opacity .3s ease-in-out;
transition: opacity .3s ease-in-out;
padding: 2px 6px;
//固定在代码块的右上角,父relative+子fixed==>父relative+子absolute,这里可以根据自己的情况做调整fixed或者absolute
//父relative+子fixed
position: fixed;
margin-top: 2px;
//父relative+子absolute
//position: absolute;
//top: 5px;
right: 5px;
opacity: 0;
}
.btn-copy span {
margin-left: 5px;
}
.highlight:hover .btn-copy{
opacity: 1;
}
1
@require "macPanel"

2. 整合步骤

新增整合的js逻辑代码:themes/next/source/js/src/highlight-wrap.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
/**
* @author qcmoke
* @description "mac面板"和"代码全选复制"
* @Dependencies https://github.com/zenorocha/clipboard.js
* @version 2.0
*/

function initMacPanel() {
var highlights = $(".highlight").not(".gist .highlight");
for (var i = 0; i < highlights.length; i++) {
var figure = $(highlights[i]);
var css = figure.attr("class");
var patt = /highlight(\s?)([a-zA-Z]*)/;
patt.test(css);
//得到第二个小括号的内容,如果为空,则设置为plain
var language = RegExp.$2 || "plain";
var newDiv = $("<div>")
.attr("data-rel", language.toUpperCase())
.addClass("highlight-wrap");
var wrap = figure.wrap(newDiv);
wrap.before(
'<button class="copy-btn" data-clipboard-snippet=""><i class="fa fa-clipboard"></i></button>'
);
}
}

function initClipboard() {
var clipboard = new ClipboardJS(".copy-btn", {
target: function(trigger) {
//return trigger.nextElementSibling;//返回复制按钮下一个列表选项的 HTML 内容
///返回复制按钮所在dom下含有class为code的第一个dom对象(可以防止复制figcaption的内容)
var wrap = trigger.parentElement;
var code = wrap.querySelector(".code");
return code;
}
});
clipboard.on("success", function(e) {
var button = e.trigger;
var iElement = button.querySelector("i");
iElement.className = "fa fa-check";
button.onmouseleave = function(ev) {
e.clearSelection();
setTimeout(function() {
iElement.className = "fa fa-clipboard";
}, 1000);
};
});
}

$(document).ready(function() {
initMacPanel();
initClipboard();
});

修改页面模板引擎文件:themes/next/layout/_scripts/pages/post-details.swig,在最后追加如下代码以引入第三方插件依赖 clipboard.min.js和以上的 highlight-wrap.js

1
2
3
<!-- 代码块包裹面板=mac面板+代码块全选复制按钮 -->
<script type="text/javascript" src="{{ url_for(theme.js) }}/src/clipboard.min.js?v={{ theme.version }}"></script>
<script type="text/javascript" src="{{ url_for(theme.js) }}/src/highlight-wrap.js?v={{ theme.version }}"></script>

第三方插件:clipboard.js, 或者直接下载 (右键另存为)。如果之前没有下载clipboard.min.js,那么需要下载并保存 clipboard.min.js文件到 theme/next/source/js/src

新增整合的自定义样式文件:themes/next/source/css/_custom/highlight-wrap.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
/**
* @author qcmoke
* @description "mac面板"和"代码全选复制"样式
* @version 2.0
*
* tips: 修改hexo next主题配置文件,设置代码高亮highlight_theme为night eighties
*/
.highlight-wrap {
position: relative;
}

.highlight-wrap:hover .copy-btn, .highlight-wrap .copy-btn:focus {
opacity: 1;
}

.copy-btn {
position: absolute;
top: 2px;
right: 2px;
display: inline-block;
padding: 2px 6px;
outline: 0;
border: none;
background: inherit;
color: #dfe2e5;
vertical-align: middle;
white-space: nowrap;
font-weight: 600;
font-size: 14px;
line-height: 16px;
opacity: 0;
cursor: pointer;
transition: opacity .3s ease-in-out;
user-select: none;
}

.highlight-wrap {
margin-bottom: 1.6em;
padding-top: 30px;
border-radius: 5px;
background: #21252b;
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, .4);

&::before {
position: absolute;
top: 1px;
padding: 0 80px;
color: #fff;
content: attr(data-rel);
font-weight: 700;
font-size: 14px;
}

.highlight {
margin: 0 !important;
border-radius: 0 0 5px 5px;

&::before {
position: absolute;
left: 12px;
margin-top: -20px;
width: 12px;
height: 12px;
border-radius: 50%;
background: #fc625d;
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
content: ' ';
}

// 代码选中时的样式
::selection {
background: #2593a6;
color: #fff;
}

// 代码块标题栏
figcaption {
margin: 0;
padding: 0 .5em .35em;
padding-right: 8px;
padding-left: 27px;
border-bottom: 1px solid #111;
background-color: #21252b;
color: #999;
font-style: italic;
line-height: 1em;

a {
float: right;
color: #2770c3;
}

a:hover {
border-bottom: 1px solid #d9534f;
color: #d9534f;
}
}

// 防止调试代码块内边框出现白线的问题
table>tbody>tr:nth-of-type(odd) {
background-color: unset;
}

.code {
+mobile() {
//background: #2593a6;
color: #fff;
}
}

// 操作系统设置缩放比例比较大的时候适当调整代码字体变大
@media (min-width: 1600px) {
pre {
font-size: 14px;
}
}
}
}

修改主题自定义样式文件:themes/next/source/css/_custom/custom.styl,在最后追加如下代码以引入整合的样式:

1
@require "highlight-wrap"

💁‍♂温馨提示:

custom.styl中最好不要出现其他与高亮有关的样式,如果存在的话可能会与上面的样式冲突。如果发现最终效果不理想,可以尝试在custom.styl中注释掉冲突的css代码。

建议修改hexo next主题配置文件,设置代码高亮 highlight_themenight eighties,这样效果会更好。

效果:

image-20200223011734366

四十八、美化标签云

新建 themes/next/layout/tag-color.swig文件,拷贝如下内容:

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
    {########彩色标签云##########}
<script type="text/javascript">
var alltags = document.getElementsByClassName('tag-cloud-tags');
var tags = alltags[0].getElementsByTagName('a');
for (var i = 0; i < tags.length; i++) {
//console.log(tags[i]);
//默认next会根据文章的数量确定a标签字的大小,这里把字体修改成统一大小
tags[i].style.background = "rgb(67, 67, 67)";
tags[i].style.fontSize = "13px";
tags[i].style.color = "#ddd";
}
</script>

<style>
.tag-cloud-tags{
text-align: center;
counter-reset: tags;
margin-bottom: 20px;
}
.tag-cloud-tags a{
border-radius: 6px;
padding-right: 5px;
padding-left: 5px;
margin: 8px 5px 0px 0px;
}
.tag-cloud-tags a:before{
content: "🔖";
}
.tag-cloud-tags a:hover{
box-shadow: 0px 5px 15px 0px rgba(0,0,0,.4);
transform: scale(1.1);
transition-duration: 0.15s;
}
</style>

themes/next/layout/page.swig里引入 tag-color.swig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        {# tagcloud page support #}
{% if page.type === "tags" %}
<div class="tag-cloud">
<div class="tag-cloud-title">
{{ _p('counter.tag_cloud', site.tags.length) }}
</div>
<div class="tag-cloud-tags">
{{ tagcloud({min_font: 12, max_font: 30, amount: 300, color: true, start_color: '#ccc', end_color: '#111'}) }}
</div>
</div>

+ {########彩色标签云##########}
+ {% include 'tag-color.swig' %}

{% elif page.type === 'categories' %}
<div class="category-all-page">

四十九、自定义友情链接页面

方案1 纯静态文件

创建 myblog/source/links-falls/index.md

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
---
title: 友情链接
date: 2020-02-18 22:32:49
no_toc: true
comments: true
---

<!-- more -->

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/links-falls/link.css">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="/static/links-falls/link.js" type="text/javascript"></script>
</head>
<body>
<div>
<div class="links-content">
<div class="link-navigation"></div>
</div>
</div>
</body>
</html>


------

<div style="text-align:center;">
<span class="with-love" id="animate1"><i class="fa fa-heart"></i></span>
留言互换友链鸭
<span class="with-love" id="animate2"><i class="fa fa-heart"></i></span>
</div>

------

{% note success %}

## 友链格式

- 昵称:Qcmoke
- 网站地址:[https://www.qcmoke.site](https://www.qcmoke.site)
- 网站Logo:[https://www.qcmoke.site/images/logo.jpg](https://www.qcmoke.site/images/logo.jpg)

{% endnote %}

myblog/source/static/目录分别创建文件

linklist.json

1
2
3
4
5
6
7
8
9
10
11
12
[
{
"nickname": "Qcmoke",
"avatar": "https://www.qcmoke.site/images/logo.jpg",
"site": "https://www.qcmoke.site"
},
{
"nickname": "Qcmoke",
"avatar": "https://www.qcmoke.site/images/logo.jpg",
"site": "https://www.qcmoke.site"
}
]

添加友链的话,只要在这个json文件里添加数据即可。

link.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
$(function() {
link = {
init: function() {
const that = this;
/*加载 linklist.json 文件路径*/
$.getJSON("/static/links-falls/linklist.json", function(data) {
that.render(data);
});
},
render: function(data) {
let html,
nickname,
avatar,
site,
li = "";
for (let i = 0; i < data.length; i++) {
nickname = data[i].nickname;
avatar = data[i].avatar;
site = data[i].site;
// 将数据拼接成html
li +=
'<div class="card">'
+'<a href="' +site +'" target="_blank">' +'<div class="thumb" style="background: url( ' + avatar +');">' +"</div>" + "</a>"
+'<div class="card-header">' +'<span class="card-site-nickname"><a href="' +site +'" target="_blank">' +nickname +"</a></span>" +"</div>" +
"</div>";
}
$(".link-navigation").append(li);
},
};
link.init();
});

link.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
.links-content {
margin-top: 1rem;
}

.link-navigation::after {
content: " ";
display: block;
clear: both;
}

.card {
width: 60px;
height: 100px;
font-size: 0.5rem;
padding: 0;
border-radius: 4px;
transition-duration: 0.15s;
margin-bottom: 1rem;
display: block;
float: left;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background: #f5f5f5;
}

.card {
margin-left: 16px;
}
.card {
margin-right: 16px;
}

.card:hover {
transform: scale(1.1);
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
}

.card .thumb {
width: 100%;
height: 0;
border-radius: 50%;
padding-bottom: 100%;
background-size: 100% 100% !important;
}

.posts-expand .post-body img {
margin: 0;
padding: 0;
border: 0;
}

.card .card-header {
display: block;
text-align: center;
padding: 1rem 0.25rem;
font-weight: 500;
color: #333;
white-space: normal;
}

.card .card-header a {
font-style: normal;
color: #2bbc8a;
font-weight: 700;
text-decoration: none;
border: 0;
}

.card .card-header a:hover {
color: #d480aa;
text-decoration: none;
border: 0;
}

.card-site-nickname {
white-space: nowrap; /*强制span不换行*/
display: inline-block; /*将span当做块级元素对待*/
width: 100%; /*限制宽度*/
overflow: hidden; /*超出宽度部分隐藏*/
text-overflow: ellipsis; /*超出部分以点号代替*/
line-height: 0.9; /*数字与之前的文字对齐*/
}

.card-site-nickname:hover {
overflow: visible; /* 内容显示在元素框外面 */
}

需要在 myblog/_config.yml中添加如下配置,表示不进行渲染的目录或者文件

1
2
skip_render:
- static/**

最后修改主题配置文件 themes/next/_config.xml文件,把链接加入到菜单栏

1
2
3
4
5
6
7
menu:
home: / || home
categories: /categories/ || th
tags: /tags/ || tags
archives: /archives/ || archive
+ links: /links-falls/ || link
about: /about/ || user

效果:

image-20200220155325572

方案2 模板引擎swig

新建 themes/next/layout/links.swig文件,并复制粘贴以下内容

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
{% block content %}
{######################}
{### LINKS BLOCK ###}
{######################}

<div id="links">
<style>
div#links {
margin-top: 20px;
}
.card {
/* 两列 */
/* width: 35%;
padding: 10px 20px; */

/* 三列 */
width: 30%;
padding: 10px 11px;
margin: auto 6px;

/* 四列 */
/* width: 20%;
padding: 10px 20px; */

font-size: 1rem;
border-radius: 4px;
transition-duration: 0.15s;
box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.12);
margin-bottom: 1rem;
background: #f5f5f5;
display: flex;
float: left;
}

/* pc 缩放100% */
@media (min-width: 1600px) {
.card{
width: 29%;
}
}

/* pc 缩放125%*/
@media (min-width: 1024px) {
.main-inner {
width: 1024px;
}
.links-content {
margin-top: 1rem;
width: 100%;
}
.link-navigation::after {
content: " ";
display: block;
clear: both;
}
/* .card:nth-child(odd) {
float: left;
}
.card:nth-child(even) {
float: right;
} */
}

/* ipad pro */
@media (max-width: 1024px) {
.card {
width: 30%;
padding: 10px 11px;
margin: 0 6px 1rem 6px;
}
}
@media (max-width: 1023px) {
.main-inner {
width: unset;
}
.card {
margin-left: 5rem;
width: 85%;
}
.links-content {
width: unset;
}
.card:nth-child(odd) {
float: none;
}
.card:nth-child(even) {
float: none;
}
}

/* ipad */
@media (max-width: 768px) {
.card {
margin-left: 4rem;
width: 80%;
}
}

/* iphone7/7 plus */
@media (max-width: 767px) {
.card {
margin-left: 2rem;
width: 76%;
}
}

/* iphone 5/se */
@media (max-width: 320px) {
.card {
margin-left: 1rem;
width: 82%;
}
}

.card:hover {
/* transform: scale(1.1); */
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
}
.card a {
border: none;
}
.card .ava {
width: 3rem !important;
height: 3rem !important;
margin: 0 !important;
margin-right: 1em !important;
border-radius: 50%;
}
.card .card-header {
font-style: italic;
overflow: hidden;
width: 100%;
}
.card .card-header a {
font-style: normal;
font-weight: bold;
text-decoration: none;
}
.card .card-header a:hover {
color: #222;
text-decoration: none;
}
.card .card-header .info {
font-style: normal;
color: #a3a3a3;
font-size: 12px;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
span.focus-links {
font-style: normal;
margin-left: 10px;
position: unset;
left: 0;
padding: 0 7px 0 5px;
font-size: 11px;
border-radius: 40px;
line-height: 24px;
height: 22px;
color: #fff !important;
background-color: #555;
display: inline-block;
}
span.focus-links:hover {
background-color: #222;
}
.friends-btn {
text-align: center;
color: #555 !important;
background-color: #fff;
border-radius: 3px;
font-size: 15px;
box-shadow: inset 0 0 10px 0 rgba(0, 0, 0, 0.35);
border: none !important;
transition-property: unset;
padding: 0 15px;
margin: inherit;
}
.friends-btn:hover {
color: rgb(255, 255, 255) !important;
border-radius: 3px;
font-size: 15px;
box-shadow: inset 0px 0px 10px 0px rgba(0, 0, 0, 0.35);
background-image: linear-gradient(
90deg,
#a166ab 0%,
#ef4e7b 25%,
#f37055 50%,
#ef4e7b 75%,
#a166ab 100%
);
margin: inherit;
}

</style>
<div class="links-content">
<div class="link-navigation">
{% for link in theme.mylinks %}
<div class="card">
<img class="ava" src="{{ link.avatar }}" style="border: none"/>
<div class="card-header">
<div><a href="{{ link.site }}" target="_blank"> {{ link.nickname }}</a> <a href="{{ link.site }}"><span class="focus-links">关注</span></a></div>
<div class="info" title="{{ link.info }}">{{ link.info }}</div>
</div>
</div>
{% endfor %}
</div>
{{ page.content }}
</div>
</div>

{##########################}
{### END LINKS BLOCK ###}
{##########################}
{% endblock %}

然后修改 themems/next/layout/page.swig文件,根据上下文找到相关位置然后添加如下两处 +号相关的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  {% block title %}{#
#}{% set page_title_suffix = ' | ' + config.title %}{#

#}{% if page.type === "categories" and not page.title %}{#
#}{{ __('title.category') + page_title_suffix }}{#
#}{% elif page.type === "tags" and not page.title %}{#
#}{{ __('title.tag') + page_title_suffix }}{#
+ <!-- 友情链接-->
+ #}{% elif page.type === 'links' and not page.title %}{#
+ #}{{ __('title.links') + page_title_suffix }}{#
#}{% else %}{#
#}{{ page.title + page_title_suffix }}{#
#}{% endif %}{#
#}{% endblock %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    {% elif page.type === 'categories' %}
<div class="category-all-page">
<div class="category-all-title">
{{ _p('counter.categories', site.categories.length) }}
</div>
<div class="category-all">
{{ list_categories() }}
</div>
</div>
+ <!-- 友情链接-->
+ {% elif page.type === 'links' %}
+ {% include 'links.swig' %}
{% else %}
{{ page.content }}
{% endif %}
</div>

新建 hexo/source/links/index.md友链文件,在标题头中写入 type = "links" 这个属性头,如下:

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
---
title: 友情链接
date: 2018-10-05 22:39:06
no_toc: true
comments: true
type: "links"
---

------

<div style="text-align:center;">
<span class="with-love" id="animate1"><i class="fa fa-heart"></i></span>
留言互换友链鸭
<span class="with-love" id="animate2"><i class="fa fa-heart"></i></span>
</div>

------

{% note default %}

### 友链格式

- 昵称:Qcmoke
- 链接:[https://www.qcmoke.site](https://www.qcmoke.site)
- 头像:[https://www.qcmoke.site/images/logo.jpg](https://www.qcmoke.site/images/logo.jpg)
- 描述:一个快乐的小码农!

{% endnote %}

修改主题配置文件 themes/next/_config.xml文件,把链接加入到菜单栏

1
2
3
4
5
6
7
menu:
home: / || home
categories: /categories/ || th
tags: /tags/ || tags
archives: /archives/ || archive
+ links: /links/ || link
about: /about/ || user

最后,添加友链的话,只要在主题配置文件 themes/next/_config.xml文件末尾添加相关友情信息即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 友情链接
mylinks:
- nickname: Qcmoke # 昵称
avatar: https://www.qcmoke.site/images/logo.jpg # 头像地址
site: https://www.qcmoke.site #友链地址
info: Peace & Love ! Learning to think independently !
- nickname: Qcmoke
avatar: https://www.qcmoke.site/images/logo.jpg
site: https://www.qcmoke.site
info: Peace & Love ! Learning to think independently !
- nickname: Qcmoke
avatar: https://www.qcmoke.site/images/logo.jpg
site: https://www.qcmoke.site
info: Peace & Love ! Learning to think independently !

效果:

image-20200220162053521

五十、添加热门文章页面

💁‍♂说明:

这里添加热门文章页面的原理是通过leancloud访问统计生成的数据实现的,故需要编辑 themes/next/_config.yml主题配置文件开启 leancloud_visitors的功能。具体操作请参考上文的“leancloud统计”。

创建 themes/next/layout/top.swig文件

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
{% block content %}
{######################}
{### LINKS BLOCK ###}
{######################}

<div id="top"></div>
<script src="/js/src/av-min.js"></script>
<script>
var siteUrl = "https://www.qcmoke.site"
var appId = '{{ theme.leancloud_visitors.app_id }}'
var appKey = '{{ theme.leancloud_visitors.app_key }}'
AV.initialize(appId, appKey)
var time = 0
var title = ""
var url = ""
var query = new AV.Query('Counter');
query.notEqualTo('id', 0);
query.descending('time');
query.limit(1000);
query.find().then(function (todo) {
for (var i = 0; i < 1000; i++) {
var result = todo[i].attributes;
time = result.time;
title = result.title;
url = result.url;
var content = "<p>" + "<font color='#1C1C1C'>" + "【文章热度:" + time + "℃】" + "</font>" + "<a href='" + siteUrl + url + "'>" + title + "</a>" + "</p>";
document.getElementById("top").innerHTML+=content
}
}, function (error) {
console.log("error");
});
</script>

<style>
.post-description {
display: none;
}
</style>

{##########################}
{### END LINKS BLOCK ###}
{##########################}
{% endblock %}

💁‍♂ 提醒:

如果你的博客使用了 Valine 评论系统,那么可能会有代码冲突问题。需要修改 themes/next/layout/_third-party/comments/valine.swig 加入 {% if page.comments %}这个判断条件,默认旧版的next没有这个条件。可参考上文“增强版valine”相关代码。

编辑 themes/next/layout/page.swig,修改两处代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  {% block title %}{#
#}{% set page_title_suffix = ' | ' + config.title %}{#

#}{% if page.type === "categories" and not page.title %}{#
#}{{ __('title.category') + page_title_suffix }}{#
#}{% elif page.type === "tags" and not page.title %}{#
#}{{ __('title.tag') + page_title_suffix }}{#
<!-- 友情链接-->
#}{% elif page.type === 'links' and not page.title %}{#
#}{{ __('title.links') + page_title_suffix }}{#
+ <!-- top页面-->
+ #}{% elif page.type === 'top' and not page.title %}{#
+ #}{{ __('title.top') + page_title_suffix }}{#
#}{% else %}{#
#}{{ page.title + page_title_suffix }}{#
#}{% endif %}{#
#}{% endblock %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  {% elif page.type === 'categories' %}
<div class="category-all-page">
<div class="category-all-title">
{{ _p('counter.categories', site.categories.length) }}
</div>
<div class="category-all">
{{ list_categories() }}
</div>
</div>
<!-- 友情链接-->
{% elif page.type === 'links' %}
{% include 'links.swig' %}
+ <!-- top页面-->
+ {% elif page.type === 'top' %}
+ {% include 'top.swig' %}
{% else %}
{{ page.content }}
{% endif %}
</div>

创建 myblog/source/top/index.md文件

1
2
3
4
5
6
7
---
title: 文章阅读量排行榜
type: top
comments: false
keywords: top,文章阅读量排行榜,热文,文章热度,热门文章
description: 博客文章阅读量排行榜
---

然后编辑 themes/next/_config.yml,添加菜单项

1
2
3
4
5
6
7
8
menu:
home: / || home
categories: /categories/ || th
tags: /tags/ || tags
archives: /archives/ || archive
links: /links/ || link
about: /about/ || user
热文: /top/ || fire

五十一、文章底部加上评分小星星

淘宝买东西,作为消费者的我们,看评价很重要。现在作为博主,写了一篇文章,很期待读者的反馈。而与淘宝一样,确认收货后,相比评论,更愿意五星好评。那么博客文章怎么加上呢?首先打开主题配置文件:

1
2
3
4
5
6
# Star rating support to each article.
# To get your ID visit https://widgetpack.com
rating:
enable: true
id: 23****
color: fc6423

先去https://widgetpack.com注册个帐号,填一下自己博客的信息,把左上角的 ID值,填进上面的 rating.id中,color改成自己喜欢的即可。

💁‍♂说明:

  1. 可以配置评分方式,侧栏 > Rating > Setting,建议用 IP address 或 Device(cookie),免登录,毕竟 Socials 里面的选项几乎都被墙,不适合国内网络环境。
  2. 建议在侧栏 > Site > Setting 中勾选 Private 选项。
  3. 上面两步勾选后别忘了点击页面右下方的 SAVE SETTING 绿色按钮保存。

如果你想给评分的星星周围加内容,可以修改文件:themes/next/layout/_macro/post.swig,例如添加下面 +相关的内容:

1
2
3
4
5
6
{% if theme.rating.enable %}
<div class="wp_rating">
+ <div style="color: rgba(0, 0, 0, 0.75); font-size:13px; letter-spacing:3px">(>看完记得五星好评哦亲<)</div>
<div id="wpac-rating"></div>
</div>
{% endif %}

五十二、优化首页摘要

为了减小首页摘要文字的大小,使得能够更美观,可通过下面步骤修改:

编辑 themes/next/layout/_macro/post.swig。加入如下div。

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
{% if is_index %}
+ <div class="index-content">
<!-- 自定义摘要图片开始 -->
{% if post.summary_img %}
<div class="out-img-topic">
<img src={{ post.summary_img }} class="img-topic">
</div>
{% endif %}
<!-- 自定义摘要图片结束 -->
<!-- 自定义摘要描述开始 -->
{% if post.summary_description %}
<div class="post-button text-center">
<div>{{ post.summary_description }}</div>
</div>
{% endif %}
<!-- 自定义摘要描述结束 -->
{% if post.description and theme.excerpt_description %}
<div class="post-button text-center">
<div>{{ post.description }}</div>
</div>
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% elif post.excerpt %}
{{ post.excerpt }}
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}{% if theme.scroll_to_more %}#{{ __('post.more') }}{% endif %}" rel="contents">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% elif theme.auto_excerpt.enable %}
{% set content = post.content | striptags %}
{{ content.substring(0, theme.auto_excerpt.length) }}
{% if content.length > theme.auto_excerpt.length %}...{% endif %}
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="{{ url_for(post.path) }}{% if theme.scroll_to_more %}#{{ __('post.more') }}{% endif %}" rel="contents">
{{ __('post.read_more') }} »
</a>
</div>
<!--/noindex-->
{% else %}
{% if post.type === 'picture' %}
<a href="{{ url_for(post.path) }}">{{ post.content }}</a>
{% else %}
{{ post.content }}
{% endif %}
{% endif %}
+ </div>
{% else %}
{{ post.content }}
{% endif %}

然后编辑 themes/next/source/css/_custom/custom.styl并加入如下样式:

1
2
3
4
// 摘要文字
.index-content {
font-size: 12px;
}

五十三、暗黑模式

编辑 themes/next/layout/_scripts/vendors.swig文件,在最文件底部加入如下代码

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
<!-- 暗黑模式 -->
<i id="darkmode" class="fa fa-lightbulb-o" aria-hidden="true"></i>
<script>
// 依次判断 系统暗黑模式 缓存 dark
var body = $("body")
var darkmode = $("#darkmode")
if (matchMedia("(prefers-color-scheme: dark)").matches ||localStorage.getItem("darkmode") === "1") {
if (!(localStorage.getItem("noDark") === "1")) {
body.addClass("dark")
}
}
body.hasClass("dark")?darkmode.removeClass("fa-moon-o").addClass("fa-lightbulb-o"):darkmode.removeClass("fa-lightbulb-o").addClass("fa-moon-o")
darkmode.click(function () {
if (body.hasClass("dark")) {
darkmode.removeClass("fa-lightbulb-o").addClass("fa-moon-o")
body.removeClass("dark")
localStorage.setItem("darkmode", "0")
localStorage.setItem("noDark", "1")
} else {
darkmode.removeClass("fa-moon-o").addClass("fa-lightbulb-o")
body.addClass("dark")
localStorage.setItem("darkmode", "1")
localStorage.setItem("noDark", "0")
}
})
</script>

创建 themes/next/source/css/_custom/dark.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
/* 黑暗切换模式按钮 */
#darkmode {
position: fixed;
z-index: 1050;
cursor: pointer;
right: 33px;
bottom: 91px;
left: unset;
font-size: 20px;
width: 1rem;

@media (max-width: 960px) {
right: 25px;
bottom: 110px;
}
}

/* 平滑改变背景色 */
* {
transition: background-color 1000ms; // transition: color 500ms, background-color 1000ms;
}

/* 下面是暗黑模式下的个性化定制样式 */
:root {
--dark-background-color: #222;
--dark-post-background-color: #292a2d;
--dark-color: #a9a9b3;
--dark-a-hover-color: #6190e8;
}

.dark {
background-color: var(--dark-background-color);
color: var(--dark-color);

::selection {
background: #f4e1c0;
color: #101012;
text-shadow: none;
}

/* 在深色模式下把图片亮度调到 70% */
img {
-webkit-filter: brightness(0.7) !important;
filter: brightness(0.7) !important;
}

a {
color: var(--dark-color);

:hover {
color: var(--dark-a-hover-color);
}
}

.header {
.menu {
background-color: #565555;

.menu-item {
a {
color: var(--dark-color);

:hover {
color: var(--dark-color);
}
}
}


@media (max-width: 767px) {
background-color: var(--dark-background-color);
}

}
}


.post {
background-color: var(--dark-post-background-color);
}

.main-inner .post {
background-color: var(--dark-post-background-color);
box-shadow: 0 0 10px 0 #555;

.archive {
box-shadow: unset;
}

/* 代码行 */
code {
color: #eee;
background: #555;
}
}

.posts-expand {
.post-title-link {
color: var(--dark-color);
}

table>tbody>tr:nth-of-type(odd) {
background-color: #202225;
}
}

.highlight-wrap {
background: #1d1d1d;

.copy-btn {
border: unset;
background-color: unset;
color: var(--dark-color);
}

table>tbody>tr:nth-of-type(odd) {
background-color: unset;
}
}

blockquote {
border-left-color: #666;
color: #929191;
}

.posts-expand .post-body img {
border: unset;
}

/* mac代码面板 */
.highlight-wrap {
.highlight .gutter pre {
background-color: unset;
color: #666;
}

.highlight .code pre {
background-color: unset;
border-left-color: #333;
}

.highlight,
pre {
background: #202225;
color: var(--dark-color);
}
}

.highlight-wrap::before {
color: #ccc;
}

/* 分页 */
.pagination {
.page-number.current {
color: #333;
background: #ccc;
}
}

.pagination .next,
.pagination .page-number,
.pagination .prev {
border-top-color: #333;
}

/* 文章底部 */
.post-footer {
.post-widgets {
border-top-color: #666;

#needsharebutton-postbottom .btn {
color: #333;
background-color: var(--dark-color);
}

#needsharebutton-postbottom .btn:hover {
background-color: #f6f6f6;
}
}

.post-nav {
border-top: 1px solid #666;

.post-nav-item a:hover {
color: var(--dark-a-hover-color);
}
}
}

/* 评论面板 */
.comments {
.tablink {
color: #222;
}

.tablink:hover {
background-color: #ddd;
}

.currentTabcontent {
background-color: #ddd;
}

.tabcontent-li {
border-color: #757474;

/* gitalk */
.gt-container {
.gt-comment-body {
color: var(--dark-color) !important;
}

.gt-meta {
border-bottom: #333;
}

.gt-header-textarea {
background-color: var(--dark-post-background-color);
}

.gt-comment-content {
background-color: var(--dark-post-background-color);
}

.gt-comment-content:hover {
-webkit-box-shadow: 0 0.625em 3.75em 0 #f4f4f4;
box-shadow: 1px 1px 1em 0 #222;
}

.gt-user .gt-ico svg {
fill: #ccc;
}

.gt-header-preview {
background-color: var(--dark-post-background-color);
color: var(--dark-color);
}
}

.valine {
* {
color: var(--dark-color);
}

border-bottom: #333;

.vwrap {
border: var(--dark-post-background-color);

.textarea-wrapper {
background: unset;
}

.textarea-wrapper .comment_trigger {
background-color: var(--dark-post-background-color);
}

.textarea-wrapper textarea {
color: var(--dark-color);
background-color: var(--dark-post-background-color);
}

.auth-section .input-wrapper input {
color: var(--dark-color);
background-color: var(--dark-post-background-color);
}

.auth-section {
background-color: var(--dark-post-background-color);
}

.auth-section .post-action button {
border: var(--dark-post-background-color);
background-color: #202124;
}
}

.vlist .vcard .text-wrapper .vhead .vname {
color: var(--dark-a-hover-color);
}
}
}
}

.post-toc {
a {
:hover {
color: #ccc;
}
}

.nav .active-current>a {
color: #87daff;
}
}

/* 本地搜索面板 */
.local-search-popup {
background: #333;
}

/* 归档页 */
.archive {
.posts-collapse .post-title a {
color: var(--dark-color);
}

.posts-collapse::after {
background: var(--dark-post-background-color);
}
}

/*阅读排行榜*/
#top font {
color: var(--dark-color);
}

/* 友情链接 */
#links {
.card {
.card-header a {
color: #333;
}

.card-header .info {
color: #60676d;
}
}
}
}

编辑 themes/next/source/css/_custom/custom.styl,在此文件中的最后引入 dark.styl样式文件

1
@require 'dark';

五十四、最新版custom.styl

custom.styl版本是随着博客的更新而一直在维护的最新版本。不确保适配其他博客的hexo next Muset布局,如果想要第一版 custom.styl,可以移步到本文“魔改Muset布局”。

themes/next/source/css/_custom/custom.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
352
// 去掉链接下的下划线
* a {
text-decoration: none;
border-bottom: unset;
}

// 页面顶部样式
.header {
// 顶部背景
background-image: linear-gradient(90deg, #222325, #3b3c3f, #222325);

@media (max-width: 767px) {
background: black;
}

// 顶部宽度和距离
.header-inner {
padding-top: 0;
padding-bottom: 0;
width: 100%;
}

// 博客title
.custom-logo-site-title .brand {
background: none;

.site-title {
letter-spacing: 0;
font-weight: bold;
font-size: 29px;
}
}

// 博客subtitle描述
.site-subtitle {
margin-top: 7px;
margin-bottom: 5px;
color: #999;
font-weight: 700;
font-size: 10px;

@media (max-width: 767px) {
display: block;
margin-top: 11px;
padding-bottom: 2px;
}
}

// 顶部菜单栏
.menu {
margin-top: 0;
margin-bottom: 0;
padding: 1px;
background-color: rgba(255, 255, 255, .75);
box-shadow: 0 10px 10px 0 rgba(0, 0, 0, .15);
text-align: center;

// 菜单超链接
.menu-item a {
padding-right: 20px;
padding-left: 20px;
color: #333;
font-weight: 600;
font-size: 13px;

@media (min-width: 1600px) {
font-size: 15px;
}

:hover {
color: black;
font-weight: bold;
}
}
}

// 移动端下拉抽屉按钮横杠背景色
.site-nav-toggle .btn-bar {
background: #f9f9f9;
}

// 移动端下拉抽屉面板上边距
.site-nav {
top: 62px;
}
}

// 首页主体部分
.main {
// 首页文章缩略卡片宽度
section#posts {
margin: 0 auto;
width: 78%;

@media (min-width: 1600px) {
margin: 0 auto;
width: 83%;
}

@media (max-width: 767px) {
margin: 0 auto;
width: 85%;
}

@media (max-width: 960px) {
margin: 0 auto;
width: 85%;
}

// 缩略图边缘样式
.post-body img {
padding: 0;
border: none;
}
}

// 缩略图指定宽度值显示。
img.img-topic {
width: 55%;

@media (max-width: 767px) {
width: 60%;
}
}

// 去除缩略卡片之间的分割线
.posts-expand .post-eof {
margin: 0;
background-color: rgba(255, 255, 255, 0);
}

// 页码
.pagination {
// 减小页码外边距
margin: 50px 0 0;
// 去除页面底部页码上面的横线
border: none;
}
}

// 主体文章
.main-inner {
// 文章宽度
margin: 0 auto;
width: 960px;

@media (min-width: 1600px) {
width: 1080px;
}

@media (max-width: 960px) {
margin: 0 auto;
width: inherit;
}

@media (max-width: 767px) {
margin: 0 auto;
width: inherit;
}

.post {
margin-bottom: 10px;
padding: 45px 28px 36px;
background-color: rgb(255, 255, 255);
box-shadow: 0 0 10px 0 rgba(0, 0, 0, .5);

@media (max-width: 767px) {
padding: 45px 12px 36px;
}
}

.posts-expand {
// 文章标题字体
.post-title {
font-weight: 700;
font-size: 20px;
}

// 文章元数据(meta)留白更改
.post-meta {
margin: 10px 0 20px;
}

// 文章的描述description
.post-meta .post-description {
margin-top: 30px;
margin-bottom: 0;
color: #666;
font-style: italic;
font-size: 14px;
}

@media (max-width: 767px) {
margin: 0;
padding-top: 0;
}

@media (max-width: 960px) {
margin: 0;
}
}

// 摘要文字
.index-content {
font-size: 12px;
}

// 文章内链接文本样式
.post-body p a {
border-bottom: none;
border-bottom: 1px solid #0593d3;
color: #0593d3;

&:hover {
border-bottom: none;
border-bottom: 1px solid #fc6423;
color: #fc6423;
}
}

// 文章底部
.post-footer {
.post-widgets {
padding-top: 0;

// 当rating和needmoreshare2都开启时让它们居中竖着排
if (hexo-config('rating.enable') && hexo-config('needmoreshare2.enable')) {
#needsharebutton-postbottom {
bottom: 25px;
margin: auto 50%;
}

.wp_rating {
position: relative;
top: 35px;
}
}
}

.post-nav {
margin-top: 30px;
}
}
}

// 侧栏抽屉
#sidebar {
// 近期文章
.sidebar-inner li.recent_posts_li {
text-align: center;
}

@media (max-width: 767px) {
.site-overview {
overflow-x: hidden;
overflow-y: auto;
}
}
}

// 侧方浮动抽屉按钮
.sidebar-toggle {
@media (max-width: 767px) {
right: 20px;
bottom: 58px;
width: 20px;
height: 20px;
opacity: unset;

.sidebar-toggle-line {
height: 3px;
}
}
}

// 回到顶部按钮
.back-to-top {
@media (max-width: 960px) {
right: 20px;
}

@media (max-width: 767px) {
right: 20px;
}
}

// 博客页面最底部
.footer-inner {
// 移动端footer字体变小,防止换行
@media (max-width: 767px) {
font-size: 11px;
}
}

// 分类页
.category-all-page {
.category-list {
margin: 0;
margin-left: 44%;
padding: 0;
list-style: none;
}

a.category-list-link {
font-weight: bold;
font-size: 20px;
}
}

// 归档页位置调整
.posts-collapse {
margin-top: 50px;

.post-header::before {
left: -4px;
}

.collection-title {
margin: 50px 0 5px;
}

.post {
margin: 0;
margin-top: 0;
margin-left: 2px;
padding: 2px;
box-shadow: none;
}

.post-header {
position: relative;
border-bottom: 1px dashed #ccc;
transition-delay: 0s;
transition-timing-function: ease-in-out;
transition-duration: .2s;
transition-property: border;
}
}

// 热文页
#top p {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

// 引入其他文件的样式
@require 'scrollbar';
@require 'comments';
@require 'highlight-wrap';
@require 'dark';

💁‍♂下面的文件是 custom.styl依赖的样式文件:

(1)themes/next/source/css/_custom/scrollbar.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
/**
* @author qcmoke
* 美化博客中浏览器的滚动条(只适用于webkit内核浏览器)
*/
@media (min-width: 567px) {
/* 定义滚动条高宽及背景高宽分别对应横竖滚动条的尺寸 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
background-color: #F5F5F5;
}

/* 定义滚动条轨道内阴影+圆角 */
::-webkit-scrollbar-track {
border-radius: 2px;
background-color: #F5F5F5;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
}

/* 定义滑块内阴影+圆角 */
::-webkit-scrollbar-thumb {
border-radius: 2px;
background-color: #555;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
}
}

(2)themes/next/source/css/_custom/comments.styl

➡️⏫ 参考上文“整合多个评论面板”的 comments.styl

(3)themes/next/source/css/_custom/highlight-wrap.styl

➡️⏫ 参考上文“mac代码面板整合全选复制按钮”的 highlight-wrap.styl

(4)themes/next/source/css/_custom/dark.styl

➡️⏫ 参考上文“暗黑模式”的 dark.styl

五十五、添加备案号

修改 themes/next/layout/_layout.swig,在footer标签里添加a链接标签,如下:

1
2
3
4
5
6
7
8
9
10
<footer id="footer" class="footer">
<div class="footer-inner">
{% include '_partials/footer.swig' %}
{% include '_third-party/analytics/analytics-with-widget.swig' %}
{% if theme.beian.enable %}
<a href="{{url_for(theme.beian.url)}}" target="_blank">{{theme.beian.beianNum}}</a>
{% endif %}
{% block footer %}{% endblock %}
</div>
</footer>

然后修改主题配置文件 themes/next/_config.ymll添加如下配置:

1
2
3
4
beian:
enable: true
url: https://beian.miit.gov.cn/
beianNum: 黔ICP备20002951号

五十六、推荐文章

📚https://easyhexo.com

📚https://io-oi.me/tech/hexo-next-optimization

📚https://www.liaofuzhan.com/posts/2114475547.html



----------- 本文结束 -----------




如果你觉得我的文章对你有帮助,你可以打赏我哦~
0%