Hexo Blog

Hexo介绍

Hexo 是一个基于 Node.js 的快速、简洁且高效的博客框架,用 Markdown 写作,插件和主题多,可快速搭建个人博客。

安装 Node.js

Hexo 的运行环境

https://nodejs.org/zh-cn/download

选择LTS稳定正式版

检查是否安装成功

1
node -v && npm -v

安装 Git

https://git-scm.com/downloads

1
brew install git

检查是否安装成功

1
git -v

安装 Hexo

https://hexo.io/zh-cn/

npm 全局安装 Hexo

1
npm install -g hexo-cli

检查是否安装成功

1
hexo -v

搭建 Hexo 博客

初始化博客

1
hexo init 自定义文件名
1
cd 自定义文件名

安装依赖

1
npm install

启动本地服务器

1
2

hexo s

访问 http://localhost:4000 查看

初始化后文件结构

1
2
3
4
5
6
7
8
自定义文件名
├── _config.yml Hexo配置文件
├── package.json #项目信息
├── scaffolds
├── source #存放页面和文章,_posts里存放文章
| ├── _drafts
| └── _posts
└── themes #存放主题

核心操作命令

创建新文章

1
hexo new "文章名"

创建新页面

1
hexo new page "页面名"

hexo clean 清除缓存和生成文件

1
hexo cl

hexo generate 生成静态文件

1
hexo g

hexo server 启动本地服务器

1
hexo s

hexo deploy 部署到服务器

1
hexo d

修改后内容后,可以使用以下命令清理缓存重新生成静态文件并启动服务器

1
hexo cl && hexo g && hexo s

修改配置

网站配置

1
2
3
4
5
6
7
8
# Site
title: KZero's Blog #网站标题
subtitle: 'Accumulation record' # 网站副标题
description: '好记性不如烂键盘' # 网站描述
keywords: KZero Blog # 网站关键字,支持多个关键词
author: CodeKZero # 您的名字
language: en #zh-CN # 网站使用的语言
timezone: ''

URL配置

1
url: http://zoiii.cn

highlight配置(新版本可能缺少 enable: true 而无法使用)

1
2
3
4
5
6
highlight:
line_number: true
auto_detect: false
tab_replace: ''
wrap: true
hljs: false

修改

1
2
3
4
5
6
7
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace: ''
wrap: true
hljs: false

Live2D配置

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
# Live2D
# https://github.com/EYHN/hexo-helper-live2d
live2d:
enable: true
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-hijiki # npm-module package name
use: PLT #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: right
width: 280
height: 426
superSample: 2 #超级样本
hOffset: -82 #偏移量
vOffset: -82 #垂直偏移
# 互动增强配置
# click: true # 开启点击互动
# mouseover: true # 开启鼠标悬停互动
# auto: true # 自动播放待机动作
# hover: true # 显示互动提示文字
# hoverTips: # 自定义提示文字
# default: "想和我玩吗?"
# touch: "哎呀!别碰我!"
# click: "点击我有惊喜哦~"
mobile:
show: false # 手机中是否展示
scale: 0.6 # 移动设备上的缩放
hHeadPos: 0.2 # 在移动设备上水平方向头部位置调整 (百分比,影响模型在屏幕上的水平定位)
vHeadPos: 0.1 # 在移动设备上垂直方向头部位置调整 (百分比,影响模型在屏幕上的垂直定位)
# react:
# opacityDefault: 0.7 # 看板娘默认的不透明度 (0 完全透明 - 1 完全不透明)
# opacityOnHover: 0.8 # 当鼠标悬停在看板娘上时的不透明度

搜索配置

1
2
3
4
5
6
# 搜索功能
search:
path: search.xml
field: post
format: html
limit: 10000

Hexo NexT 配置

安装 NexT 主题

根目录

1
git clone https://github.com/next-theme/hexo-theme-next.git themes/next

_config.yml 修改

1
theme: next

theme/next/_config.yml 修改

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

修改

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

修改配置

添加自定义页面

添加archives/categories/tags/about/links页面
添加归档、分类、标签、关于我、友情链接页面

修改配置

theme/next/_config.yml 修改

1
2
3
4
5
6
7
8
9
10
menu:
home: / || fa fa-home # 首页
categories: /categories/ || fa fa-th # 分类系统
archives: /archives/ || fa fa-archive #chart-diagram #archive # 文章归档
tags: /tags/ || fa fa-tags # 标签云
about: /about/ || fa fa-robot #user # 关于页面
Friend: /links/ || fa fa-user-group #users # 友情链接
# schedule: /schedule/ || fa fa-calendar # 日程表
# sitemap: /sitemap.xml || fa fa-sitemap # 站点地图
# commonweal: /404/ || fa fa-heartbeat # 公益404页

添加 archives 页面

开启后,默认自带不用操作

添加 categories 页面

1
hexo new page "categories" 

source/categories/index.md 修改

1
2
3
4
5
6
---
title: Categories
date: 2025-06-16 16:07:13
type: categories
comments: false
---

添加 tage 页面

1
hexo new page "tags"

source/tags/index.md 修改

1
2
3
4
5
6
---
title: Tags
date: 2025-06-16 16:07:40
type: tags
comments: false
---

添加 about 页面

1
hexo new page "about"

source/about/index.md 修改

1
2
3
4
5
6
7
8
9
10
11
12
---
title: About Me
date: 2025-06-16 16:07:45
type: about
---

Hello~ I'm KZero

来自福建,是个爱折腾爱探索的动漫日剧爱好者,热衷于各种科技产品和好用效率的软件,喜欢简洁舒适科技的御宅生活。
喜欢编程,虽然整天研究一些无用的东西,但每天过充实而快乐。
喜欢游戏,Apex、守望先锋、星际争霸、冒险岛...
喜欢运动,户外、骑行、篮球、乒乓球...
1
hexo new page "links"

source/links/index.md 修改

1
2
3
4
5
6
7
8
9
10
11
12
---
title: Friend Links
date: 2025-06-16 16:07:54
type: links
---

欢迎在下面留言申请友情链接~格式如下

> 名称:KZero
描述:Coding / Hiking / Photog / Music
博客地址:http://zoiii.cn
头像地址:http://zoiii.cn/img/avatar.gif

theme/next/layout/ 新建 links.njk(可修改友链样式)

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

<div id="links">
<style>

#links{
margin-top: 5rem;
}

.links-content {
width: 100%;
}

.link-navigation{
overflow: hidden;
display: inline-block;
padding: 0 0 7px;
}

.card {
height: 70px;
width: 300px;
display: block;
color: #666;
line-style-type: none;
text-decoration: none;
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
transition: box-shadow .25s cubic-bezier(.4, 0, .2, 1);
margin: 10px;
float: left;
border: 0;
}

.card:hover {
text-decoration: none;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
}

.card .ava {
float: left;
height: 70px;
width: 70px;
margin: 0;
}

.card-header {
overflow: hidden;
height: 70px;
width: 230px;
margin-left: 70px;
font-size: 15px;
}

.nickname {
text-align: center;
height: 25px;
width: 100%;
line-height: 12px;
margin: 14px 0 0;
}

.info {
text-align: center;
height: 20px;
width: 100%;
margin: 0;
line-height: 12px;
color: #777;
font-size: 12px;
}
</style>
<div class="links-content">
<div class="link-navigation">

{% for link in theme.mylinks %}

<a href="{{ link.site }}" target="_blank" class="card">
<img class="ava" src="{{ link.avatar }}"/>
<div class="card-header">
<div class="nickname">{{ link.nickname }}</div>
<div class="info">{{ link.info }}</div>
</div>
</a>

{% endfor %}

</div>
{{ page.content }}
</div>
</div>

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

theme/next/layout/page.njk 引入

1
2
3
    <!-- 友情链接-->
{%- elif page.type === 'links' and not page.title %}
{{- __('title.links') + page_title_suffix }}

引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{% block title %}
{%- set page_title_suffix = ' | ' + 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 === 'schedule' and not page.title %}
{{- __('title.schedule') + 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
  <!-- 友情链接-->
{% elif page.type === 'links' %}
{%- include 'links.njk' -%}

引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="post-body{% if page.direction and page.direction.toLowerCase() === 'rtl' %} rtl{% endif %}">
{%- if page.type === 'tags' %}
{%- include '_partials/page/tags.njk' -%}
{% elif page.type === 'categories' %}
{%- include '_partials/page/categories.njk' -%}

<!-- 友情链接-->
{% elif page.type === 'links' %}
{%- include 'links.njk' -%}

{% elif page.type === 'schedule' %}
{%- include '_partials/page/schedule.njk' -%}
{% else %}
{{ page.content }}
{%- endif %}
</div>

theme/next/_config.yml 添加

1
2
3
4
5
6
7
# 友链
mylinks:

- nickname: # 名字
info: # 描述
site: # 网站地址
avatar: # 头像

添加搜索功能

theme/next/_config.yml 修改

1
2
local_search:
enable: true

安装搜索插件

1
npm install hexo-generator-searchdb --save

添加 Live2D

根目录

1
npm install hexo-helper-live2d --save

_config.yml 添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Live2D
## https://github.com/EYHN/hexo-helper-live2d
live2d:
enable: true #是否启用
scriptFrom: local # 脚本来源,可以是local或jsdelivr等CDN
pluginRootPath: live2dw/ # 插件在站点上的根目录(相对路径)
pluginJsPath: lib/ # 插件JS目录
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-hijiki # npm-module package name
use: PLT #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: right
width: 280
height: 426
superSample: 2 #超级样本
hOffset: -82 #偏移量
vOffset: -82 #垂直偏移
mobile:
show: true # 手机中是否展示
scale: 0.6 # 移动设备上的缩放
hHeadPos: 0.2
vHeadPos: 0.618
react:
opacityDefault: 0.7
opacityOnHover: 0.8

根目录下新建 live2dw 文件夹用来存放Live2D模型,通过配置文件选取模型

添加 APlayer

添加 APlayer

找个地方下载APlayer只需要里面dist文件

1
git clone https://github.com/DIYgod/APlayer

aplayer/dist 里新建 music.js 添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const ap = new APlayer({
container: document.getElementById('aplayer'),
fixed: true,
autoplay: false,
loop: 'all',
volume: 0.7, //默Ï认音量Ï
listFolded: true,
listMaxHeight: 60,
audio: [
{
name: "Welcome to Chew Chew",
artist: 'Asteria',
url: 'https://music.163.com/song/media/outer/url?id=435403078.mp3',
cover: 'https://p1.music.126.net/Epju_XiNiSWoafctIg68JQ==/17940731230636690.jpg',
}
]
});

music.js 内容可根据:APlayer官方文档 进行配置

把 dist 放入 theme/next/source

在 hexo-blog\themes\next\layout_layout.njk 在body标签后 –>

1
2
3
4
5
<!-- 添加aplayer -->
<link rel="stylesheet" href="/dist/APlayer.min.css">
<div id="aplayer"></div>
<script type="text/javascript" src="/dist/APlayer.min.js"></script>
<script type="text/javascript" src="/dist/music.js"></script>

网易云音乐链接

网易云音乐复制歌曲链接

1
https://music.163.com/song?id=取这里的id值&userid=423945766

链接模版:

1
https://music.163.com/song/media/outer/url?id=把id值添加到这里.mp3

获取头像F12选取链接

CloudflareR2 获取音乐链接

下载好 .mp3 音乐
网易云音乐下载音乐有些可能是 ncm 格式
音频 ncm 格式转 mp3
https://www.zhuanhuanyun.cn/?to=.zh-warp

Cloudflare R2:https://dash.cloudflare.com/

R2 Object Storage –> Create bucket

Bucket name: music
Location: Automatic –> Provide a location hint (optional) –Asia-Pacific (APAC)
Default Storage Class –> Standard

Settings –> Public Development URL –> Enable -> 输入allow –> Allow

Objects –> select from computer –> Files上传下载好的 .mp3 音乐 –> 点进上传好的音乐 –> 复制URLs

添加 Gitalk 评论

新建Github仓库

https://github.com/new

新建一个仓库用来存储评论,评论将会存储仓库 Issue 中

注册GitHub OAuth应用

https://github.com/settings/applications/new

Application name: Gitalk
Homepage URL: http://blog.zoiii.cn
Authorization callback URL: http://blog.zoiii.cn
Enable Device Flow
Register application

获取Client ID 和 Client Secret

修改配置

themes/next/_config.yml 修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
gitalk:
enable: true
github_id: zoiiiiii # GitHub 仓库所有者
repo: gitalk # 用于存储 issues 的仓库名称
client_id: # 获取的Client ID
client_secret: # 获取的Client Secret
admin_user: zoiiiiii # GitHub 仓库所有者和协作者,只有这些人可以初始化 GitHub issues
distraction_free_mode: true # 类似 Facebook 的无干扰模式
# 当官方代理不可用时,可以更改为自己的代理地址
proxy: https://cors-anywhere.azm.workers.dev/https://github.com/login/oauth/access_token # 这是官方代理地址
# Gitalk 的显示语言取决于用户的浏览器或系统环境
# 如果希望访问您网站的所有人都看到统一的语言,可以设置强制语言值
# 可选值: en | es-ES | fr | ru | zh-CN | zh-TW
language: en

添加黑白模式切换

根目录

1
npm install hexo-next-darkmode --save

themes/next/_config.yml 添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Darkmode JS
# For more information: https://github.com/rqh656418510/hexo-next-darkmode, https://github.com/sandoche/Darkmode.js
darkmode_js:
enable: true
bottom: '16px' # default: '32px'
right: '96px' # default: '32px'
left: 'unset' # default: 'unset'
time: '0.5s' # default: '0.3s'
mixColor: 'transparent' # default: '#fff'
backgroundColor: 'transparent' # default: '#fff'
buttonColorDark: '#121212' # default: '#100f2c'
buttonColorLight: '#121212' # default: '#fff'
isActivated: false # default false
saveInCookies: false # default: true
label: ◑ # default: ''
autoMatchOsTheme: false # default: true
libUrl: # Set custom library cdn url for Darkmode.js

SEO 优化

生成 sitemap.xml

1
npm install hexo-generator-sitemap --save

生成 RSS

1
npm install hexo-generator-feed --save

自动推送至搜索引擎

1
npm install hexo-seo-autopush --save

自定义

themes/next/source/css/_schemes/Gemini/index.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
// 自定义样式

.site-title {
font-size: 15px !important;
}

// .main-menu {
// font-size: 14px;
// }

.main-inner {
font-size: 14px;
}

.fa-tags {
font-size: 15px;
}

.live2d-widget-container {
z-index: 999 !important;
}

/* 暗黑模式切换按钮样式 */
body .darkmode-toggle {
width: 26px !important;
height: 26px !important;
border-radius: 0 !important;
opacity: 0.8;
color: #fff;
font-size: 16px;
z-index: 999 !important;
}

/* 手机端响应式样式 */
@media (max-width: 576px) {
/* 移动端隐藏音乐播放器 */
.aplayer {
display: none !important;
}

/* 手机端调整暗黑模式按钮位置 */
.darkmode-toggle {
bottom: 24px !important;
right: 16px !important;
}

.sidebar-toggle {
right: 16px;
left: auto;
}
}

/* 平板响应式样式 */
@media (min-width: 577px) and (max-width: 991px) {
/* 平板设备显示音乐播放器 */
.aplayer {
display: block !important;
}
.sidebar-toggle {
right: 96px;
left: auto;
}
.darkmode-toggle {
bottom: 24px !important;
right: 96px !important;
}
}

// 平板以下样式
@media (max-width: 768px) {
.darkmode-toggle {
width: 26px !important;
}
}

@media (min-width: 1200px) {
.main {
width: 1120px;
}
}

@media (max-width: 1201px) {
.main {
width: 1180px;
}
}

themes/next/layout/_macro/sidebar.njk

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
{% macro render(display_toc) %}
<aside class="sidebar">
{%- if display_toc %}
{%- set toc = toc(page.content, {class: 'nav', list_number: page.toc.number, max_depth: page.toc.max_depth}) %}
{%- set display_toc = toc.length > 1 and display_toc %}
{%- endif %}

<div class="sidebar-inner {% if display_toc %}sidebar-nav-active sidebar-toc-active{% else %}sidebar-overview-active{% endif %}">
<ul class="sidebar-nav">
<li class="sidebar-nav-toc">
{{ __('sidebar.toc') }}
</li>
<li class="sidebar-nav-overview">
{{ __('sidebar.overview') }}
</li>
</ul>

<div class="sidebar-panel-container">
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
{%- if display_toc %}
<div class="post-toc animated">{{ toc }}</div>
{%- endif %}
</div>
<!--/noindex-->

<div class="site-overview-wrap sidebar-panel">
{{ partial('_partials/sidebar/site-overview.njk', {}, {cache: theme.cache.enable}) }}

{{- next_inject('sidebar') }}

{# 移动到这里 #}
{%- if theme.links %}
<div class="links-of-blogroll animated">
<div class="links-of-blogroll-title">
{%- if theme.links_settings.icon %}<i class="{{ theme.links_settings.icon }} fa-fw"></i>{% endif %}
{{ __('sidebar.links') }}
</div>
<ul class="links-of-blogroll-list">
{%- for blogrollText, blogrollURL in theme.links %}
<li class="links-of-blogroll-item">
{{ next_url(blogrollURL, blogrollText, {title: blogrollURL}) }}
</li>
{%- endfor %}
</ul>
</div>

{%- endif %}
</div>
</div>

{%- if theme.back2top.enable and theme.back2top.sidebar %}
<div class="back-to-top animated" role="button" aria-label="{{ __('accessibility.back_to_top') }}">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
{%- endif %}
</div>

{# 移动到上面 #}
{#
{%- if theme.links %}
<div class="sidebar-inner sidebar-blogroll">
<div class="links-of-blogroll animated">
<div class="links-of-blogroll-title">
{%- if theme.links_settings.icon %}<i class="{{ theme.links_settings.icon }} fa-fw"></i>{% endif %}
{{ __('sidebar.links') }}
</div>
<ul class="links-of-blogroll-list">
{%- for blogrollText, blogrollURL in theme.links %}
<li class="links-of-blogroll-item">
{{ next_url(blogrollURL, blogrollText, {title: blogrollURL}) }}
</li>
{%- endfor %}
</ul>
</div>
</div>
{%- endif %}
#}

{%- if theme.related_posts.enable %}
{%- if theme.pjax %}
<div class="pjax">
{%- endif %}
{%- if page.related_posts and page.related_posts.length > 0 %}
<div class="sidebar-inner sidebar-post-related">
<div class="animated">
{{ partial('_partials/post/post-related.njk') }}
</div>
</div>
{%- endif %}
{%- if theme.pjax %}
</div>
{%- endif %}
{%- endif %}
</aside>
{% endmacro %}