Hexo博客个性化配置

个性化的内容越来越多,About页面放不下了,于是决定单独写一篇文章记录本博客的配置

主题

NexT.Gemini

  • 版本:v8.10.1

不建议用npm安装,因为那样没法魔改。所以一如既往的直接clone就可以了。

背景图片(ribbon)

本来打算上传背景的,但是图片太大了,最后采用了动态生成的ribbon。

在博客的_config.yml,把canvas_ribbon的enable设置成true。

但是原版的ribbon.js有个小问题,就是如果在手机上点击,会连续刷新两次背景。看了一眼代码,问题出在这儿。

1
2
document.onclick = redraw;
document.ontouchstart = redraw;

这里我把ontouchstart给删了,同时也就不能用CDN提供的js文件了。

好在hexo允许自行配置vendors。在next的_config.yml里头找到vendors项目,然后在canvas_ribbon填上自己的js文件路径。

1
2
# 这里js文件被我放在 next\source\js\ribbon.min.js
canvas_ribbon: /js/ribbon.min.js

音乐播放器

APlayer

  • 版本:v1.10.1
  • 安装方法:把该项目的dist文件夹复制到themes\next\source
  • 页面跳转不打断播放:在主题的_config.yml,把pjax设置成true

要让播放器生效,需要修改_layout.njk

1
2
3
4
5
6
7
# 路径:themes\next\layout\_layout.njk
# 在<div class="headband"></div>下方插入这些内容

<link rel="stylesheet" href="/aplayer/APlayer.min.css">
<div id="aplayer"></div>
<script type="text/javascript" src="/aplayer/APlayer.min.js"></script>
<script type="text/javascript" src="/aplayer/music.js"></script>

使用csv文件来管理曲库,配合Python脚本自动生成music.js

配置

大部分配置项都可以在Aplayer文档找到,这里仅列出我改过的配置。

  • fixed(吸底模式): true
  • preload(预加载): ‘metadata’
  • autoplay(自动播放): false
  • order(播放顺序): ‘random’

注意:预加载默认是开启的。反正大部分人也不会点播放器,所以只加载metadata就能有效地节约流量。

自动生成music.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
import csv
import json

filename = 'musicDB.csv'
repo_url = 'https://oscarcx.com/hexo_resource/music/'

# 从csv读取name和artist并去掉表头
with open(filename, encoding='UTF-8') as f:
reader = csv.reader(f)
music_list = list(reader)[1:]

# 生成JSON对象
# music_list[i] = [name, artist, url, cover]
# url / cover 为空时,会使用name代替
result = []
for i in range(len(music_list)):
data = {}
data['name'] = music_list[i][0]
data['artist'] = music_list[i][1]
mp3_file_name = music_list[i][2] if music_list[i][2] else music_list[i][0]
data['url'] = repo_url + 'song/' + mp3_file_name + '.mp3'
cover_name = music_list[i][3] if music_list[i][3] else music_list[i][0]
data['cover'] = repo_url + 'cover/' + cover_name + '.jpg'
result.append(data)

# 写入music.js
with open('music.js', 'w', encoding='UTF-8') as f:
f.writelines([
"const ap = new APlayer({" + "\n",
" container: document.getElementById('aplayer')," + "\n",
" fixed: true," + "\n",
" preload: 'metadata'," + "\n",
" autoplay: false," + "\n",
" order: 'random'," + "\n",
" audio: ",
])
json.dump(result, f, ensure_ascii=False, sort_keys=False, indent=4)
f.write("});")

魔改footer

显示hexo和next版本号

页脚显示版本号这个特性在v7的next主题是有的,但是v8给去掉了。我个人比较喜欢这个特性,于是琢磨了半天nunjucks,把显示版本号给魔改回来了。

在footer.njk中把对应内容替换成下面这些~

1
2
3
4
5
6
7
8
9
10
11
12
13
// themes\next\layout\_partials\footer.njk

{%- if theme.footer.powered %}
<div class="powered-info">
<span class="post-meta-item">
{{- __('footer.powered', next_url('https://hexo.io', 'Hexo', {class: 'theme-link'}) + ' v' + hexo_version) }}
</span>
<span class="post-meta-item">
{%- set next_site = 'https://theme-next.js.org' if theme.scheme === 'Gemini' else 'https://theme-next.js.org/' + theme.scheme | lower + '/' %}
{{- __(' 主题 – ' + next_url(next_site, 'NexT.' + theme.scheme, {class: 'theme-link'}) + ' v' + next_version) }}
</span>
</div>
{%- endif %}

然后在locals.js替换下面内容

1
2
3
4
5
6
7
// themes\next\scripts\filters\locals.js

// 替换 const { config } = hexo;
const { version, config } = hexo;

// 添加下面这行
locals.hexo_version = version;

版权信息和字数统计并排

这个也是v7的next主题有的特性,升级到v8又给改没了。。。

这个改起来就很简单了,无非就是把字数统计的span放到版权信息的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
<div class="copyright">
{%- set copyright_year = date(null, 'YYYY') %}
&copy; {% if theme.footer.since and theme.footer.since != copyright_year %}{{ theme.footer.since }} – {% endif %}
<span itemprop="copyrightYear">{{ copyright_year }}</span>
<span class="with-love">
<i class="{{ theme.footer.icon.name }}"></i>
</span>
<span class="author" itemprop="copyrightHolder">{{ theme.footer.copyright or author }}</span>


{%- if config.symbols_count_time.total_symbols or config.symbols_count_time.total_time %}
{%- if config.symbols_count_time.total_symbols %}
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-chart-line"></i>
</span>
{%- if theme.symbols_count_time.item_text_total %}
<span>{{ __('symbols_count_time.count_total') + __('symbol.colon') }}</span>
{%- endif %}
<span title="{{ __('symbols_count_time.count_total') }}">{{ symbolsCountTotal(site) }}</span>
</span>
{%- endif %}

{%- if config.symbols_count_time.total_time %}
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-coffee"></i>
</span>
{%- if theme.symbols_count_time.item_text_total %}
<span>{{ __('symbols_count_time.time_total') }} &asymp;</span>
{%- endif %}
<span title="{{ __('symbols_count_time.time_total') }}">{{ symbolsTimeTotal(site, config.symbols_count_time.awl, config.symbols_count_time.wpm, __('symbols_count_time.time_minutes')) }}</span>
</span>
{%- endif %}
{%- endif %}
</div>

页面载入动画速度

v7的主题也没这个问题,升级到v8之后,首页加载文章的动画速度慢的令人抓狂。在打了不少断点之后,终于搞清楚next主题是如何控制动画速度的了。

hexo的动画是由motion.js进行组装,然后交给anime.js(CDN提供)执行。其中anime.js里头有个参数叫duration,默认值是200,作用是控制动画执行的时间(也就是速度)。这个默认值是在博客的motion.js里头设定的,如下所示。

1
2
3
4
const timeline = window.anime.timeline({
duration: 200,
easing : 'linear'
});

motion.js里头还有个参数叫deltaT,作用是在默认时间基础上进行偏移,如下所示。

1
2
3
4
sequence.forEach(item => {
if (item.deltaT) timeline.add(item, item.deltaT);
else timeline.add(item);
});

那么要改变动画速度,直接修改对应的deltaT就可以了,这里拿文章载入动画速度为例。这里自带的deltaT是-=100,那么duration算出来是100,所以才感觉拖泥带水。最后我改成了-=200,此时duration是0,然后动画就变得干脆利索了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// themes\next\source\js\motion.js

postList: function() {
const sequence = [];
const { post_block, post_header, post_body, coll_header } = CONFIG.motion.transition;

function animate(animation, selector) {
if (!animation) return;
document.querySelectorAll(selector).forEach(targets => {
sequence.push({
targets,
complete: () => targets.classList.add('animated', animation),
deltaT : '-=200'
});
});
}

animate(post_block, '.post-block, .pagination, .comments');
animate(coll_header, '.collection-header');
animate(post_header, '.post-header');
animate(post_body, '.post-body');

return sequence;
}

字数统计和阅读时长

hexo-word-counter

  • 版本:v0.0.3
  • 代码块不计入字数(exclude_codeblock: true)

注意:安装完之后一定要执行hexo clean

阅读进度条

next主题的_config.yml里找到Reading progress bar开启

首页隐藏分类(比如公告)

hexo-generator-index2

  • 版本:v0.2.0

禁用更新日期

next主题的_config.yml > post_meta > updated_at > enable: false

全英语链接

全英语链接方便搜索引擎收录,这里简单修改hexo站点的_config.yml即可,下面给出本博客的配置

我的.md文件名都是英语,所以URL > permalink可以设置为:category/:title.html

文章的类别大多都是中文名,可以通过Category & Tag > category_map进行映射

1
2
3
4
5
6
# URL
:category/:title.html

# Category & Tag
category_map:
技术: tech

图片延迟加载(lazyload)

lazyload就是延迟加载,只有在看到图片的时候才加载,从而加快网页载入速度。

next主题的_config.yml,把lazyload设置成true

图片缩放(mediumzoom)

mediumzoom是一个点击放大图片的插件,挺实用的。

next主题的_config.yml,把mediumzoom设置成true

其它改动

全部统一放在 source_data\styles.styl

然后把next主题的_congif.yml的这部分取消注释就可以了。写在这个文件里的css会被添加到末尾,所以可以直接覆盖默认样式。

1
2
3
4
5
# Define custom file paths.
# Create your custom files in site directory `source/_data` and uncomment needed files below.
custom_file_path:
(省略若干)
style: source/_data/styles.styl

放弃的魔改

代码块自动换行

路径:next\source\css_common\scaffolding\highlight\index.styl

1
2
3
4
5
6
.code pre {
padding-left: 10px;
// width: 100%;
white-space: pre-wrap;
word-break: break-all;
}

改完之后确实自动换行了,复制代码也不会破坏格式,但是左手边的代码行号不会改,所以只能暂时搁置。