0%

超详细:这个Hexo网站,到底是怎么做出来的?

断更好久了,今天终于抽空来写一点。不知不觉之间,这个网站已经上线运行1年多了,于是,我就开了这个新坑(Hexo网站的配置以及深度开发),应该够我写一阵子了,也算作送给这1年来的present……我也会随着教程的更新重复一遍过程,以保证内容的正确性。

顾名思义,这篇文章就记录一下我在开发这个网站时的操作过程,以及可能会遇见的一些问题。你可以在我的基础上继续深入,自由发挥!好了,闲话少说,我们这篇超详细的Hexo网站教程,马上开始!

注:本教程所用平台是Win10,其他系统可能有细微差别~由于涉及到GitHub,建议先参照3个小妙招来加个速!


1. 准备工作部分

1.1 你可能一定会用到的那些软件

为了使用Hexo这个强大的框架,我们需要先安装一些依赖,还有一些其他的编程软件。为了真的把这个教程变得“新手向”一点,我就把你需要的软件都列在了这里:

类别 必要性 名称
依赖 NodeJS
编程相关、配置网站参数 中高 (推荐)VSCodeSublime Text以及任何你用着顺手的编辑器
文章相关 (你甚至可以用记事本) (推荐)Marktext(开源免费)、Typora(付费)
命令行 Windows Terminal Preview(集成终端,支持自定义)、Git(需要配置SSH连接,暂时请先自己搜)

注:如果你使用chocolatey,你可以尝试先用命令行安装! 这些软件我们依次来说:

1.1.1 NodeJS

NodeJS是一款很流行的JavaScript运行时(环境),也是使用Hexo的必装依赖。打开安装官网,如下图,推荐选择左侧的长期支持版本(LTS版本)。

安装之后,打开命令行,输入:

1
2
node -v
npm -v

来检测是否安装成功。如果都可以成功返回版本号,那么你就可以进行下一步操作了!

注:一般情况下,官方下载源会很慢,我们需要给NodeJS修改镜像源。使用

1
npm config set registry http://registry.npm.taobao.org/

来调整为国内镜像源。

1.1.2 Markdown编辑器Marktext

周知所众,我们写博客一般都是用Markdown这种标记语言的(不会写?参见这篇Markdown教程)。纯净的界面,即时的渲染、开源与免费三大特点让我爱上了这款编辑器。别的咱也不说,好不好用你自己说了算!这个项目的开源地址在GitHub上:https://github.com/marktext/marktext/,之后怎么安装我就不用说了吧。

1.1.3 Windows终端·预览版

如果你嫌CMD或者Powershell的界面、字体不合你的心意,或者就想尝试一些新功能,你可以试一下Windows Terminal Preview。它把几个终端都打包在了一起,且支持自定义界面和启动位置等,同时可以分屏。

你可以在Microsoft Store中下载到这款终端·预览。另外,需要改一下powershell的执行策略,管理员权限执行:

1
Set-ExecutionPolicy Bypass

即可。

1.1.4 hexo,你网站的框架

上面的软件都准备好了吗?我们来安装博客框架罢。在powershell中执行:

1
npm install -g hexo-cli

就可以全局安装这个框架了。安装好之后,重启命令行,并用hexo命令检测是否安装成功:

1.2 你的repo与服务器

我们来到GitHub,并新建一个仓库,名称叫作{username}.github.io。如果你曾跟着之前的文章做过Jekyll版网站、master分支被占用的话,你可以新建一个hexo分支。注意需要勾选LICENSEREADME,这样可以形成一个master分支。

之后,你就会得到类似这样的一个页面:

然后我们转到Settings,启用(修改)GitHub Pages的相关设置,选择Deploy from a branch后勾选你的目标分支。如果你完全跟着我来的,默认是master;如果你以前动用过这个仓库,则切换到你新的分支上。如下图,点击Save就可以触发一次更新:

稍等片刻(大概1~3分钟)后,访问https://{username}.github.io(这就是你的网站域名了),如果显示的不是下面这个灰色的404,那么我们就可以开始下一步了!

注:我曾经在Jekyll那篇文章中说过,GitHub Pages会在每一次commit之后触发一次更新action,即自动化。由于需要在服务器上进行操作,可能会出现”排队“的情况,如果设置没错却迟迟出不来”非404“页面,我想,你可能需要继续等一等……


2. 初始化、主题与一些设置

2.1 让Hexo运行起来!

接下来我们就来让Hexo发挥一下它的威力罢。找到一个合适的文件夹,然后执行下面这条命令来初始化一个Hexo项目(这里以我自己为例,自己修改文件夹名):

1
hexo init hexo_website_tutorial //换上自己的文件夹名

正常情况下你获得到如下的结果:

这个时候,我们cd看一下都创建了哪些东东:

1
2
3
4
5
6
7
.
├─.github
├─node_modules
├─scaffolds
├─source
│ └─_posts
└─themes

简要说明一下:.github文件夹可以直接无视;node_modules是一些hexo本身的依赖;scaffolds里放了一些模板Markdown,暂且不用管它;source文件夹中会放我们的文章;themes文件夹则是为之后应用主题做准备。还有一个_config.yml文件,是我们网站的配置文件。

那么,我们怎么生成一个静态的网站呢?此时我们就要用到hexo generate(简称hexo g)命令了。它会读取我们写的文章,配合着主题设置生成静态文件,并复制二进制文件(图片、音频等)。注意,为了网站资源链接可以正确工作,我们要在_config.yml文件中改一行,是你网站的链接:

修改好之后,执行截图:

执行之后,我们会发现多了一个public文件夹和db.json文件。public文件夹会在生成静态文件之后复制到这里,方便上传;db.json是网站的一些meta信息,可以不用管。

生成完了,我们一定会想看一看生成后的效果。你可以使用hexo server命令在4000端口上启动一个服务器。为了方便,你可以加一个参数-o来自动打开浏览器。如下:

1
hexo s -o

4000端口上,我们的默认网站样式类似这样:

此时这个主题叫做landscape。由于我个人有更喜欢的主题(NeXT)并且landscape主题可以开发的部分不多,我们不会使用这款主题。稍后你就会知道如何切换主题。

2.2 部署到服务器

想让别人看到我们的网站,我们就要更新GitHub上的仓库,触发部署action。可是,我不希望每一次都要用3条git命令来上传,怎么办?一个好消息是,hexo提供给我们一个deploy命令。

2.2.1 远程仓库参数设置

当然了,hexo此时也不知道我们的仓库在哪里,对吧。这时候配置文件_config.yml就可以派上用场了。我们找到它的Deploy部分,并添加一些配置:

具体格式如下:

1
2
3
4
5
# Deployment
deploy:
type: 'git'
repo: git@github.com:{username}/{repo_name}.git
branch: {branch_name}

然后,我们来试一下hexo d这个命令……

诶,为什么会这样呢?Deployer not found是什么意思?原来,我们还需要安装一个官方插件:hexo-deployer-git

2.2.2 hexo-deployer-git

我们在网站根目录下执行这个命令:

1
npm i hexo-deployer-git --save

然后再执行hexo d(太长了,不用图片了):

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
INFO  Validating config
INFO Deploying: git
INFO Setting up Git deployment...
Initialized empty Git repository in D:/08 网站/hexo_website_tutorial/.deploy_git/.git/
[master (root-commit) 0b3e2b7] First commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 placeholder
INFO Clearing .deploy_git folder...
INFO Copying files from public folder...
INFO Copying files from extend dirs...
[master 3a2b089] Site updated: 2022-08-18 17:47:15
18 files changed, 5172 insertions(+)
create mode 100644 2022/08/17/hello-world/index.html
create mode 100644 archives/2022/08/index.html
create mode 100644 archives/2022/index.html
create mode 100644 archives/index.html
create mode 100644 css/fonts/FontAwesome.otf
create mode 100644 css/fonts/fontawesome-webfont.eot
create mode 100644 css/fonts/fontawesome-webfont.svg
create mode 100644 css/fonts/fontawesome-webfont.ttf
create mode 100644 css/fonts/fontawesome-webfont.woff
create mode 100644 css/fonts/fontawesome-webfont.woff2
create mode 100644 css/images/banner.jpg
create mode 100644 css/style.css
create mode 100644 fancybox/jquery.fancybox.min.css
create mode 100644 fancybox/jquery.fancybox.min.js
create mode 100644 index.html
create mode 100644 js/jquery-3.4.1.min.js
create mode 100644 js/script.js
delete mode 100644 placeholder
Enumerating objects: 34, done.
Counting objects: 100% (34/34), done.
Delta compression using up to 8 threads
Compressing objects: 100% (26/26), done.
Writing objects: 100% (34/34), 882.39 KiB | 1.49 MiB/s, done.
Total 34 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), done.
To github.com:Guleixibian2009/hexo-website-tutorial.git
+ 5066890...3a2b089 HEAD -> master (forced update)
branch 'master' set up to track 'git@github.com:Guleixibian2009/hexo-website-tutorial.git/master'.
INFO Deploy done: git

如果出现类似的结果,那我们就已经部署成功了。这个时候我们去GitHub上去,稍等一会后并访问你的网站看一下,你应该可以看到和本地端口上完全一样的页面。

2.3 切换到NexT主题

当我们可以成功的部署到GitHub上去后,我们就可以开始切换主题了。我们要用的这个主题叫做NexT,准确的说,是Gemini子主题。为了使用这个主题,我们在根目录下克隆一下GitHub上面的主题仓库theme-next/hexo-theme-next

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

然后打开根目录下的_config.yml(有区别于之后我们会用到主题内的_config.yml文件,切勿搞混):

修改过后重新生成一遍静态文件(hexo clean+hexo g),打开本地端口(hexo s -o)可以看见,我们已经切换到NexTMuse子主题了:

实际上,NexT主题分别是有4个子主题的。打开themes/next文件夹下(简称主题文件夹下_config.yml),找到95行,可以看到所有子主题,以及黑夜模式的设置(本人并未开启):

要切换到Gemini子主题,只需把第100行注释掉,并取消注释第103行即可。我们重新生成一下(还记得那3条命令吧):

主题是切换过来了,可是我看着怎么是英文的呢?或者,感觉东西太少了?还有,为什么我叫John Doe?别急,下一步,便是设置一些metadata

2.4 网站信息设置

在网站根目录下的_config.yml的开头,你可以看到这样的几条配置:

详细地解释一下(我自己先修改了):titlesubtitledescriptionauthorlanguage几项在更改后会改变下图中的对应位置,descriptionkeywordslanguagetimezone几项则是变成了网站metadata。(Ctrl+I应该可以查看)

(可能做得有些丑,谅解下哈)

回顾:hexo常用命令(以后我就不会再提醒咯)

  • 清除生成缓存——hexo clean。(对主题上的混乱或配置未生效有帮助)

  • 生成静态文件——hexo g

  • 部署到远程服务器——hexo d

  • 打开本地服务器端口——hexo s

教你几个小妙招:

  • hexo dhexo g其实可以合并成一个命令,叫做hexo g -d,就可以自动先生成再自动部署。

  • hexo s加上参数-o就可以自动在浏览器中打开端口。


3. Gemini子主题的官方配置……

现在我们就可以给我们的网站添加一些功能与细节了。先打开本地端口,让我们从左往右说:

3.1 左侧的侧边栏

左边较窄的竖栏叫sidebar(侧边栏),分为上下两部分,上半部分是一个导航栏,存放了一些站内链接;下半部分是关于你、一些网站统计数据、友情链接,这里也是我们可以自定义的地方(非官方的插件,如音乐、天气等,我们在第5节非官方插件中说)。当你打开一片博客后,下半部分也可以作为一个文章目录。下面几张图供参考:

3.1.1 添加更多的站内链接

仔细研究主题_config.yml,你会找到这样一个区块,正是关于站内链接的:

看起来,我们目前有两个可用链接(主页、归档),相对应的就是homearchive

3.1.1.1 添加链接

我们来试试取消注释abouttagscategories

诶,正好,同步增加了三个链接(不过暂时打不开)!那我们是不是就能总结出来填入的格式了?

1
2
menu:
key: /link/ || icon

key指的是链接的名字(不代表链接地址,这个名字后面还会有用),一个冒号,然后是链接地址(可相对可绝对),然后是||标识符,后面跟一个font-awesome图标名(只能用免费版的)。

掌握了语法之后,我们就可以尝试添加一个自己的链接了!假设你新建了一个歌单页面(具体操作参见后面第4节文章相关操作),它的链接是/album/,并且想要用font-awesomefas fa-compact-disc这个图标,那我们就可以在配置文件中添加这样一行:

1
2
menu:
album: /album/ || fas fa-compact-disc

在你重新生成之前,你突发奇想想要把它放在主页那个链接下面,该怎么办呢?我发现,你只需要把这一行移动到home那一行后面即可:

1
2
3
4
5
6
7
8
9
10
menu:
home: / || fa fa-home
album: /album/ || fas fa-compact-disc
about: /about/ || fa fa-user
tags: /tags/ || fa fa-tags
categories: /categories/ || fa fa-th
archives: /archives/ || fa fa-archive
#schedule: /schedule/ || fa fa-calendar
#sitemap: /sitemap.xml || fa fa-sitemap
#commonweal: /404/ || fa fa-heartbeat

效果类似这样:

可是,明明其他链接都有中文,怎么新加的album就没有?

3.1.1.2 调整i18n

别忘了,NexT主题的默认语言是英文!我们是通过修改配置强制翻译成中文的(可以回顾一下2.4节)。那…我们能不能手动翻译(学名internationalization,国际化,简称i18n)呢?其实是可以的。我们找到这个文件:

然后我们重新生成,是不是就成功了呢?

记住这个方法,我们之后也还是会用到的!

3.1.1.3 计数小“徽章”

想要显示目前我们的博客内一共有几篇文章、几个分类和几个标签吗?我们可以用一个badge解决这件事。还是刚才那段配置,有没有在下面看到一段这样的选项?

1
2
3
menu_settings:
icons: true
badges: false

我们把badges选项调成true,系统就会自动计数了。看一下效果:

嗯,光荣的0 0 1。当然现在我们的“标签”页还是打不开的。具体怎么调文章的分类或如何创建“标签”页面等,我会在第4节文章相关操作中讲到。

3.1.2 更新“综合信息中心”

我之所以把这个侧边栏的下半部分称作一个“综合数据中心”,主要是因为你几乎可以在这里放任何你想放的信息,比如你的头像、个性签名、文章相关统计、个人链接等等。(至于天气和音乐播放器我们之后会在第5节非官方插件中讲到。)这是我的网站目前的样子:

3.1.2.1 你的头像

想要给大家展示一下你的头像吗?当然可以。准备好一张照片(建议方形或圆形),移动到/public/images这个文件夹里。然后打开主题配置文件,找到如下配置:

1
2
3
4
5
6
7
8
# Sidebar Avatar
avatar:
# Replace the default image and set the url here.
url: /images/avatar.gif
# If true, the avatar will be dispalyed in circle.
rounded: true
# If true, the avatar will be rotated with the cursor.
rotated: true

url是你图片的路径,格式就是/images/再加上文件名(不一定是avatar.gif)。rounded则是选择是否要显示为圆形,rotated是选择是否要在鼠标移动到图片上时旋转。我们看一下效果如何:

注:这个黑色的N就是/images/文件夹下的logo.svg

3.1.2.2 个人链接

既然说了,这里是“综合信息中心”,那我能不能放一点个人信息(个人链接)呢?当然是可以的。最终的效果如下:

那这个是在哪里设置的呢?我们可以找到这样一段配置:

1
2
3
4
5
social:
GitHub: https://github.com/Guleixibian2009 || fab fa-github
E-Mail: mailto:guleixibian2009@outlook.com || fa fa-envelope
RSS: https://guleixibian2009.github.io/hexo-website-tutorial/atom.xml || fa fa-rss
Website: https://guleixibian2009.github.io/ || fab fa-html5

它的语法和3.1.1.1节中链接的语法是相同的,这里就不再赘述了。

3.1.2.3 Creative Commons文章版权声明

是开源项目总得有个开源许可证LICENSE吧。像博客一类非代码开源项目,我们一般选用CC版权声明。一共有6种形式(当然还有其他较特殊的协议,比如放弃权利CC0,可以自行搜索):

协议 byAttribution ncNonCommercial ndNo Derivative Works saShare Alike
转载时必须标示原作者 × × ×
标示原作者,且禁止修改 × ×
标示原作者,且禁止商用 × ×
标示原作者,且禁止修改、商用 ×
标示原作者,且禁止商用,必须相同协议 ×
标示原作者,必须相同协议 × ×

一般我们选用CC by-nc-sa这种协议。那么,我们如何直观地向别人展示呢?NexT主题内置了小图标的功能,可以找到这一部分配置文件:

1
2
3
4
5
creative_commons:
license: by-nc-sa
sidebar: true
post: false
language: deed.zh

我们选中sidebar一项,NexT就会自动渲染出一个小图标了。至于post一项,我们放到3.2节中讲。language如果需要调整为中文,直接填写deed.zh即可。看一下渲染效果:

3.1.3 文章目录

如果你现在进入那篇默认的Hello World文章,你可以在原先“信息中心”的地方看到文章的目录。那么这个目录有没有可以自定义的地方呢?也是有的。我们可以找到对应的配置:

1
2
3
4
5
6
7
8
9
10
toc:
enable: true
# Automatically add list number to toc.
number: true
# If true, all words will placed on next lines if header width longer then sidebar width.
wrap: false
# If true, all level of TOC in a post will be displayed, rather than the activated part of it.
expand_all: false
# Maximum heading depth of generated toc.
max_depth: 6

仔细观察一下生成的tocTable Of Contents,简称toc),发现每一个标题都被自动编上了号。可是,这就对像我这种习惯手动编号的人很不友好啊,我们就可以把number这个选项关掉。wrap则是说过长的标题是全部显示还是省略号,我选择了全部显示。expand_all指要不要全部展开,如果启用的话就会显示所有标题,然而像我这篇非常长的文章明显是不太合适的,所以就保持在false上。这样它就只会显示当前浏览部分的目录了。max_depth是指要生成多少层标题(1~6)。如果你不想显示过于细致的标题,可以调小。那调整之后效果类似这样:

3.2 文章板块相关配置

终于到了我们的重头戏。有一个美观的sidebar只是基础,博客最重要的就是post(即博文部分)了。官方提供的自定义不多,但还是有可以打开的功能的。(注:在3.2节中我们只会讲关于这一板块的功能,并不会讲到类似“阅读全文按钮”等。我们把它留在第4节文章相关配置里讲。)

3.2.1 文章相关信息

如果你细心的观察过文章标题下的小字,你就会发现诸如发布时间、更新时间、本文字数、分类等信息。而是否显示它们都是可以调的。

3.2.1.1 基本配置

你可以在这里找到一些基本配置:

1
2
3
4
5
6
7
8
# Post meta display settings
post_meta:
item_text: true
created_at: true
updated_at:
enable: true
another_day: true
categories: true

看起来现在所有功能都是打开的。item_text指的是要不要显示数据名称;created_at是发布时间;categories是文章的分类。由于默认的Hello World文章是没有分类的,所以它就没有显示。可是,为什么我没有看到字数统计等信息呢?原来这是通过另外一项设置实现的。

3.2.1.2 字数统计

就在post_meta一节下面,有一个symbols_count_time

1
2
3
4
symbols_count_time:
separated_meta: true
item_text_post: true
item_text_total: false

用之前我们还需要安装一个依赖,叫做hexo-symbols-count-time。直接使用npm安装即可:

1
npm i hexo-symbols-count-time --save

然后我们来看一下这些设置有什么用。item_text_post指的是要不要在文章标题下方显示本文字数&阅读时间;item_text_total则是在页脚显示全站计数。我们重新渲染来看一下效果:

3.2.2 代码块样式

在默认的Hello World文章中,有4个代码块。也许你不喜欢这种较亮的主题;或者,你不介意主题,但只是想要添加一个复制按钮?这一切的一切都是可以修改的!我们找一下对应的配置,嗯,在这里:

1
2
3
4
5
6
7
8
9
10
codeblock:
# Code Highlight theme
highlight_theme: normal
# Add copy button on codeblock
copy_button:
enable: true
# Show text copy result.
show_result: true
# Available values: default | flat | mac
style: default

高亮是默认开启的(没人不用这个功能,你真的不用的话到根目录_config.yml# Writing一节可以禁用)。你可以自己选一个喜欢的highlight_theme,我保留了normal,也就是浅色。copy_button中直接两个都调成true就可以显示复制按钮了。效果如下:

3.2.3 看见了还真不一定知道是什么的辅助功能

为了直观地展示这一节的内容,我将先超纲新建一篇文章,大家见谅哈。在这篇文章里既有中文又有英文,我还给了它一个标签,一个分类。

3.2.3.1 中英文空格——Pangu

我个人觉得中、英文混杂时没有个空格很难受,有的时候又会忘记加(就是假设,假设!)。怎么办呢?NexT提供一个功能叫做Pangu。它可以自动在中英文之间添加空格。我们找到配置:

然后改成true即可。渲染一下试试:

3.2.3.2 图片懒加载——lazyload

一路看下来,有没有发现博客中的图片都是启用了懒加载的?就在pangu的配置附近,有一个:

1
2
3
# Vanilla JavaScript plugin for lazyloading images.
# For more information: https://github.com/ApoorvSaxena/lozad.js
lazyload: false

改成true即可。它的原理就是先获取较快的占位图,再在滚动时加载新的图片。效果如下:

(是动图,压缩过,点击重新播放)

3.2.3.3 图片放大——fancybox

想要实现一个图片点击放大功能吗?fancybox可以满足你的需求。我们找到这样一段配置:

1
2
3
# FancyBox is a tool that offers a nice and elegant way to add zooming functionality for images.
# For more information: https://fancyapps.com/fancybox
fancybox: false

改成true之后我们来看一下效果:

3.2.3.4 局部刷新——pjax

想要快速的切换页面?启用pjax即可。可能很多人听说过ajax,其实pjax相当于类似的功能。

启用之前需要先用git克隆theme-next-pjax的仓库。

1
git clone https://github.com/theme-next/theme-next-pjax themes/next/source/lib/pjax

然后在配置文件中启用pjax

效果图我就不放了,动图上传起来太麻烦,得另找图床。可以自己试一下效果。

3.2.4 数学公式支持——mathjax

如果你看过这篇关于LaTex的文章的话,你可能会知道,Markdown文章中是可以添加数学公式的。那么,Hexo有没有渲染数学公式的功能呢?是有的。我们可以找到如下配置:

当然注释里也说得很清楚了,我们需要安装另一个hexo编译器,即hexo-renderer-kramed。使用如下两个命令:

1
2
npm un hexo-renderer-marked
npm i hexo renderer-kramed --save

安装即可。将enable那一行改为true,这个时候你就已经准备好MathJax了,来测试一下:

不过,使用hexo-renderer-kramed会带来一个小问题…

3.2.5 修复Todo List无法渲染的问题

这个问题是我在写Markdown语法那篇文章时发现的。虽然Todo List不是一个非常重要的语法,但我想我们最好还是修复一下这个问题:

解决办法是,打开node_modules/hexo-renderer-kramed/lib/renderer.js,并在第19行添加以下内容(对,就是查到的):

1
2
3
4
5
6
7
8
9
// Support To-Do List
Renderer.prototype.listitem = function(text) {
if (/^\s*\[[x ]\]\s*/.test(text)) {
text = text.replace(/^\s*\[ \]\s*/, '<input type="checkbox" disabled="disabled"></input> ').replace(/^\s*\[x\]\s*/, '<input type="checkbox" disabled="disabled" checked></input> ');
return '<li style="list-style: none">' + text + '</li>\n';
} else {
return '<li>' + text + '</li>\n';
}
};

修改之后重新渲染一遍即可。还是来测试一下:

  • 这是一个Todo List
  • 这是一个未被勾选的选项。

3.2.6 文末板块配置

在文章末尾一般会放置一些关于文章的额外的信息。这是我的博客文末的功能:

3.2.6.1 版权声明方框

很重视要告诉你的读者这是你的原创文章,或者觉得有必要强调自己使用了Creative Commons声明?可以考虑添加一个版权方框。至于设置的话,在这里:

post: false调整为true即可。重新生成一下,看一下效果:

当然,如果你对默认的翻译不满意的话,可以找到之前那个i18n配置文件,然后自行修改。

3.2.6.2 修改标签的小图标

仔细看,在文章末尾会显示出这篇文章的标签。在上一节的图片中,它的样式是# Test。我个人不喜欢这个#,想把它换掉。有这个功能吗?可以找到如下配置:

tag_icon一项改成true,然后重新渲染一下看看:

3.2.6.3 其他发布渠道链接(引流)

需要在文章末尾给自己其他的发布渠道(如公众号,CSDN等)或其它前端项目引流吗?我们同样可以添加一个链接方框。这是添加后的效果:

我们可以找到这样的配置:

1
2
3
4
5
6
7
# Subscribe through Telegram Channel, Twitter, etc.
# Usage: `Key: permalink || icon` (Font Awesome)
follow_me:
#Twitter: https://twitter.com/username || fab fa-twitter
#Telegram: https://t.me/channel_name || fab fa-telegram
#WeChat: /images/wechat_channel.jpg || fab fa-weixin
#RSS: /atom.xml || fa fa-rss

它的语法和3.1.1.1节的是一样的,可以参考一下。同时,如果你觉得老是修改i18n很烦的话,可以直接用你想要的名字作为Key,如:

1
2
3
4
5
6
7
8
follow_me:
#Twitter: https://twitter.com/username || fab fa-twitter
#Telegram: https://t.me/channel_name || fab fa-telegram
#WeChat: /images/wechat_channel.jpg || fab fa-weixin
RSS: /atom.xml || fa fa-rss
旧版网站: https://guleixibian.github.io/ || fab fa-html5
手写网站: https://guleixibian2009.github.io/Hand-Written-HTML-Site/ || fas fa-laptop-code
Awesome-Bootstrap项目: https://guleixibian2009.github.io/awesome-bs5/ || fab fa-bootstrap
3.2.6.4 打赏功能

在自己的网站上加几个打赏二维码还是一个不错的选择(当然我其实没有放),包括一些项目README里面也会放。预先准备好几个收款码(一定是固定的那种)或者你想放的图片,放到themes/next/source/images文件夹中。找到这样的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Reward (Donate)
# Front-matter variable (unsupport animation).
reward_settings:
# If true, reward will be displayed in every article by default.
enable: false
animation: false
#comment: Donate comment here.

reward:
#wechatpay: /images/wechatpay.png
#alipay: /images/alipay.png
#paypal: /images/paypal.png
#bitcoin: /images/bitcoin.png

这个打赏的配置有两部分。reward_settings是设置打赏按钮;图片地址要写在reward里面。先把enable调成true,然后添加几张图片试试:

1
2
3
4
5
6
7
8
9
10
11
12
reward_settings:
# If true, reward will be displayed in every article by default.
enable: true
animation: false
comment: 给作者买一杯作业...

reward:
#wechatpay: /images/wechatpay.png
#alipay: /images/alipay.png
#paypal: /images/paypal.png
#bitcoin: /images/bitcoin.png
把我的网站分享给别人吧!: /images/websiteQR.png

至于comment一行的话,是你想要在打赏按钮上方显示的句子。看一下效果:

3.3 网站上的小“零件”

这一章是关于页面上的一些(官方的)小功能。比如说(并不是所有的):

3.3.1 页脚信息显示

页脚(footer)也是稍微有一些可以调整的地方的:

我们目前的页脚是这样的:

看起来有一个版权符号,年份,作者名,还有一个爱心。但实际上,版权年份其实只会显示当前年份。如果想像我一样显示类似2021~2022,该如何实现呢?我们可以找到这样一段配置:

具体来讲一下:

  1. 被注释掉的一行since指的是站点建立的时间。把它取消注释,并改为现在的年份,就可以每年更新了(每年要重新渲染一次)。

  2. 想要让爱心动起来的话,可以把iconanimated改为true

  3. 版权默认使用项目名称,但如果希望使用我自己的名字,可以在copyright中写上自己的名字。

  4. powered指要不要显示“由Hexo强力驱动”,默认打开。

  5. beian中是网站ICP备案,我没备案就不写上了。修改完后,记得重新渲染一下。

那个计数是怎么实现的呢?那是一个第三方服务,我放在第5章中讲。

3.3.2 回到顶部按钮

看完一篇非常长的文章,如果读者想要一键返回顶部,我们就需要一个back2top按钮。基本款的默认已经有了,但是我们还可以对它进行进一步配置。

这里一共有3个选项。enable默认开启;sidebar指的是按钮的位置要不要加在侧边栏下方;scrollpercent是显示阅读百分比。我开启了第三项。最终效果:

3.3.3 阅读进度条

如何让读者清晰地看出自己已经读了多少呢?刚刚显示百分比的功能还是不错的。不过我们还有更加直观一些的方法——阅读进度条。找到这段配置:

1
2
3
4
5
6
7
# Reading progress bar
reading_progress:
enable: true
# Available values: top | bottom
position: top
color: "#37c6c0"
height: 3px

如果你不介意进度条的颜色和高度的话,直接enable: true就已经可以用了。不满意的话可以自己调整一下下面三个参数。这是最终的效果:

3.3.4 书签功能

需要在关闭页面时记录下自己的阅读进度吗?可以打开(自动)书签功能。找一下:

直接把enable调成true即可。默认的版本是auto,即关闭页面自动保存;你也可以调成manual,只在读者点击图标时保存。效果如下(自己尝试一下吧):

3.3.5 右上角GitHub徽标

虽然我们已经在侧边栏中加过一个github链接了,但我们同样可以用一个更加明显的方式为自己的github账号引流。这就是大名鼎鼎的GitHub Banner。至于配置的话,就在刚才的下面:

1
2
3
4
5
# `Follow me on GitHub` banner in the top-right corner.
github_banner:
enable: true
permalink: https://github.com/Guleixibian2009
title: Follow me on GitHub~

打开功能,先把enable调成truepermalink是指向你想要引流的链接(比如github账号,项目地址等),title是鼠标移到图标上时显示什么。来试一下:

不过如果细看的话…这个banner和书签在页面顶部时似乎有点小bug。重叠我能接受,可是露出一个角来就有点奇怪了啊!

我研究了一下,可以把书签的CSSright属性调到25px就好了。找一下/themes/next/source/css/_common/outline/header/bookmark.styl文件…不太确定这是什么语言,但是不怕!找到上面那个right(第5行那个)把那个变量名称改成25px即可了。这样就不会重叠了。

另及:使用这个变量的本意应该是想让书签的右侧和b2t按钮右侧宽度相同,但我觉得5px应该不太看的出来吧。

3.3.6 加载进度条——pace

注意到网站上加载时的蓝色加载条了吗?

这个进度条是基于pace做出来的。首先我们需要克隆pace的仓库:

1
2
cd themes/next
git clone https://github.com/theme-next/theme-next-pace source/lib/pace

然后找到对应的配置:

1
2
3
4
5
6
7
8
9
# Progress bar in the top during page loading.
# Dependencies: https://github.com/theme-next/theme-next-pace
# For more information: https://github.com/HubSpot/pace
pace:
enable: true
# Themes list:
# big-counter | bounce | barber-shop | center-atom | center-circle | center-radar | center-simple
# corner-indicator | fill-left | flat-top | flash | loading-bar | mac-osx | material | minimal
theme: minimal

我用的是minimal。重新渲染一下,看一下效果吧。

3.3.7 网站图标——favicon

直到现在我们网站的图标还是那个黑色的N。能不能改一个好看一点的呢?先找一个自己喜欢的图标,然后转成ico格式的文件(可以用convertio试试)。复制两份,分别命名16x16.ico32x32.ico。拖到themes/next/source/images文件夹里面。然后我们找到对应的配置:

1
2
3
4
5
6
7
favicon:
small: /images/16x16.ico
medium: /images/32x32.ico
#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

只保留smallmedium,再把文件名填进去即可。


4. 文章相关配置

现在我们已经把基本的一些配置好了。我们可以开始添加一些文章、页面(心心念念的标签、分类页),还可以有搜索、404页面等。你会学到如何给文章添加标签、分类等等。

4.1 关于博客——post

如果你曾注意过scaffolds文件夹里的内容,你会看到Hexo一共有3种“类型”,分别是post博客、page页面和draft草稿。我不太习惯用草稿功能,就把它放过喽。我们先来把博客讲一下:

4.1.1 新建一篇文章

还记得3.2.3节中我超纲建文章吗?建文章的命令是hexo new。如下:

1
hexo new a-new-post

然后我们就可以在source/_post里面找到一个a-new-post.md。打开看看:

文件几乎是空白的,只有一小段YML(学名YAML Front Matter)。这里面存放着关于这篇文章的元信息:

1
2
3
title: a-new-post
date: 2022-08-30 17:02:10
tags:

默认是有三个字段的,即titledatetagstitle会先默认设置为文件名,你可以改成这篇文章的标题(比如“4.1.1节新建文章示例”)。date建议不要改,是你新建文章的时间。tags是这篇文章的标签。先在文章内部写点东西试试渲染一下。我现在修改成这样,渲染一下看看:

1
2
3
4
5
6
7
8
9
10
11
---
title: 4.1.1节新建文章示例
date: 2022-08-30 17:02:10
tags:
---

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum.

4.1.2 标签与分类

现在我们尝试给文章添加一些标签和分类(照例,用Test)。只需在Front Matter中加一点即可:

1
2
3
4
5
6
7
8
title: 4.1.1节新建文章示例
date: 2022-08-30 17:02:10
tags:
- Test1
- Test2
categories:
- [Test1, Test2]
- Test3

可以看到我们添加了一个categories字段。先讲标签:新建一行,然后用-打头,空格,然后输入分类名,可以重复多行。categories中是差不多的,可是这个- []是用来干嘛的呢?这代表分类下的子分类。待会新建分类page时你就会看出来它的效果。渲染一下看看:

(为了一张图放完,这张图片是80%比例下的截图的)

4.1.3 主页节选——excerpt

我们新加的博客内容都是很短的,可以完整的放在主页上。可像我这种几k字的,主页完全放不下啊!这是我们就可以使用节选功能,同时会自动显示一个按钮,提示“继续阅读”。语法如下:

1
2
3
4
5
6
7
8
9
This is a piece of text. It's going to be very long.

<!--more-->

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum.

没错,只要在你想分开的地方加一个<!--more-->即可。我们拿Hello World那篇文章试一下:

4.1.4 文章置顶

在我的网站主页上有一篇置顶的序言,就像书的preface一样。Hexo文章在主页上的排列顺序(默认)是按发布时间后往前(即越新越往上)排布的,如何打破这个规则,强制在最上方呢?一开始我也没有查到对应的设置(都是手写进去代码),不过在翻看hexo的生成代码时(不太具体知道这是什么语言,似乎是mozilla开发的nunjucks),我注意到有一个sticky选项(而且似乎值是个数字),在这里:

1
2
3
4
5
{%- if post.sticky > 0 %}
<span class="post-sticky-flag" title="{{ __('post.sticky') }}">
<i class="fa fa-thumbtack"></i>
</span>
{%- endif %}

然后我就找到一篇post,在Front Matter里面加上这么一行:

1
sticky: 1

诶,神奇的是就好了!我在_config.yml中没有看到任何和sticky有关的配置,没想到自己摸索出来了。看一下最后的效果:

4.1.5 分页功能

目前来说,我们的主页上可能还没有几篇文章。可是,设想一下将来,当你有了几十篇博客(只是设想),难道还得全部一股脑的堆在主页上吗?我们可以尝试加一个分页功能。即:每满设定的文章数就会自动生成主页的下一页。先看一下效果吧,我是6篇一分:

找一下如下的配置(注意在Hexo配置文件内,切勿搞混了):

看起来是默认打开的啊?那我就把数值减小一点,改成6就好了。

4.2 关于页面——page

在3.1.1.1节中我们在侧边栏中添加了标签页、分类页,还有一个歌单的链接。这一章我们会把这些页面补齐,并给网站添加一个404页面。

4.2.1 新建页面

新建页面和新建一篇博客的命令是差不多的。如下,只需要在new后面添加一个page

1
hexo new page tags

tags就是所有标签页。可是,执行这个命令到底会发生什么呢?我们来看一下source文件夹。多了一个tags文件夹,里面有一个index.md。打开看看:

嗯,和post差不多,一个时间一个标题,只是没有标签和分类。然后,看一下渲染的效果,有没有这个页面了:

但这个样子肯定是有bug的。第一,它的标题怎么叫tags?第二,之前链接列表中既然有这个默认的tags,那它为什么不是自动化的,不可能连统计标签的功能都没有吧!别急,马上就把这个功能加进来,只需要一行Front Matter,再把标题改下:

1
2
title: 所有标签
type: tags

试一下渲染效果:

似乎好了耶!然后类似的,我们加一下分类、关于和歌单页,把tags分别换为categoriesaboutalbum即可。别忘了改页面的标题,并给分类页加上type: categories!这是最后的效果:

至于aboutalbum页的话,可以放自己想放的东西。

另及:还记得我们在4.1.2节中给文章添加了一个- []嵌套分类吗?现在你应该可以理解这是什么意思了吧:它表示分类下的子分类,比如“编程”,“编程-Python”等等。同时支持更多层嵌套。

4.2.2 404页面

404页面和之前的页面做起来很相似。还是用hexo new page 404这个命令来新建出页面,然后我们来添加一些配置:

1
2
3
4
5
title: ''
date: 2021-08-15 16:28:02
comments: false
sitemap: false
permalink: /404

title设为空,这样就不会显示标题。comments: false表示不在本页上加载Gitalk,详见第5章。sitemap: false表示不把本页加入站点地图,详见第6章。最重要的是这个permalink,它会声明:这个页面是通用404页面。往里面加上一些提示性的句子,比如:

1
2
3
# 404 Not Found 您访问的页面走丢了!

将于10秒后返回 [首页](https://guleixibian2009.github.io/hexo-website-tutorial) ......

渲染出来就是这样:

4.2.2.1 自动跳转功能

上面的代码块里提到了10秒后返回主页。这个是靠下面一段代码实现的:

1
2
3
<script language="javascript" type="text/javascript"> 
setTimeout("javascript:location.href='/'", 10000);
</script>

我曾经在Jekyll那篇文章里面提到过,还记得吗?直接把它粘贴到index.md末尾即可。重新渲染,可以自己去看一下效果。

4.3 关于搜索——searchdb

当我们网站上的文章渐渐多起来后,我们就需要一个方便读者找到对应文章的方式,这就是一个搜索功能。我们先安装一下对应的package

1
npm i hexo-generator-searchdb --save

不同的是,我们不能直接去找主题_config.yml内的配置,而是得先在博客配置内添加这样的配置,添在底部即可:

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

随后我们再去找这一段配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Local Search
# Dependencies: https://github.com/theme-next/hexo-generator-searchdb
local_search:
enable: false
# If auto, trigger search by changing input.
# If manual, trigger search by pressing enter key or search button.
trigger: auto
# Show top n results per article, show all results by setting to -1
top_n_per_article: 1
# Unescape html strings to the readable one.
unescape: false
# Preload the search data when the page loads.
preload: false

先把enable调成true,就可以开启功能了。然后看到top_n_per_article的选项,意思是说每篇博客显示几个结果。可以调大一点,比如调成5。我们来看一下渲染的效果。

然后顺便讲一下那个提示语是怎么改的。找到i18n文件,如下:

placeholder改成你想要的提示语即可。

4.4 如何对READMELICENSE禁用渲染

也许你已经发现,我们在第1节中创建的READMELICENSE都已经被覆盖,找不到了,就连commit都消失的无影无踪。不过,经过我的尝试,我们还是有办法添加回它们的。我们先复制这两个文件进source文件夹,然后找到主题配置:

看到那行skip_render了吗?我们用一个列表来代表禁用渲染的文件:

1
skip_render: [README.md, LICENSE]

[]就表示一个列表,每个文件名用逗号隔开即可。看一下渲染之后会发生什么:

这样,我们的README就不会被渲染成HTML了。以上这些,就是我们所有的较为基础的配置与文章相关的内容了。接下来我们会涉及到一些更高级的功能,使用到第三方插件,可以自己选择。


5. 第三方插件配置

写到这文章已经很长了,将近20k字了。不管怎么样,我们来继续我们的教程,争取再写20k啊

5.1 动态背景

读了这么久的文章了,不会还没注意到我的动态背景吧。在背景上有50个点,随机游走,相互靠近时就会连成一条线。靠近鼠标时则会被“困住”,直到再次移动鼠标。这叫做canvas_nest

另及:next其实有官方的动态背景,但我个人不满意,所以搜到了这一款。它曾经被集成入Next,但现在已不默认被集成,所以我把它归在第三方插件中。

我们先安装对应的插件,在themes/next文件夹下执行:

1
git clone https://github.com/theme-next/theme-next-canvas-nest source/lib/canvas-nest

随后我们需要新增一段yml,加在主题配置文件内,随便加在哪里。不过便于后期修改,我把它和其他动态背景放在一起。

1
2
3
4
5
6
7
8
9
# Canvas Nest
# Dependencies: https://github.com/theme-next/theme-next-canvas-nest
canvas_nest:
enable: true
onmobile: true
color: '0,0,0'
opacity: 0.5
zIndex: -1
count: 50

可以修改的有几个参数:color指线的颜色,配合opacity透明度使用;zIndex指图层,-1代表最下层;count代表最多同时出现多少条线。修改之后渲染即可。我特地给你们看一下效果:

5.2 侧边栏插件

总觉得侧边栏少了点东西,没有个性?我们可以尝试添加一些不同的东西……这是最后的效果:

5.2.1 外链播放器

音乐播放器的话是用的一个网易云的外链服务,好处在于方便(根本不需要登录什么的),快速(加载快播放也流畅)。我们先随便找一首歌(网页版的):

5.2.1.1 获取插件

看到上面的红色框框了吗?点进去,就是一个外链的生成界面:

出于兼容性的考虑我们只能用<iframe>版的,flash已经过时了。首先我们要调整一个宽度,自己觉得合适就可以。不过不要过宽,否则待会会放不下。我自己选的是280x66。然后尽量不选自动播放吧,用户体验可能不会特别好,万一读者不喜欢这首歌怎么办?然后复制下面的代码就可以了,类似这样:

1
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=280 height=86 src="//music.163.com/outchain/player?type=2&id=2080607&auto=0&height=66"></iframe>

注意一下另外两个红框,是两个相同的数字,即歌曲id。以后需要更改歌曲只要打开网页版后复制网址中的id并替换就可以了。

5.2.1.2 调整侧边栏宽度

Next主题侧边栏的宽度默认是240,这个会有点窄,要调大一点。不是说一定要比插件的宽度长,短一点也可以,它会自动的缩短。然后我这边就选了260像素。看一下配置:

5.2.1.3 插入swig模板

到现在我们已经有了一个播放器,调了宽度,可是怎么把它插入到侧边栏里来呢?我们要到模板文件里去插。找到这个文件(themes/next/layout/_partials/sidebar/site-overview.swig),在105行左右(CC之后,Blogroll之前)插入代码即可:

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
...

{%- if theme.creative_commons.license and theme.creative_commons.sidebar %}
<div class="cc-license motion-element" itemprop="license">
{%- set ccImage = '<img src="' + url_for(theme.images + '/cc-' + theme.creative_commons.license + '.svg') + '" alt="Creative Commons">' %}
{{ next_url(ccURL, ccImage, {class: 'cc-opacity'}) }}
</div>
{%- endif %}

<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=280 height=86 src="//music.163.com/outchain/player?type=2&id=2080607&auto=0&height=66"></iframe>

{# Blogroll #}
{%- if theme.links %}
<div class="links-of-blogroll motion-element">
<div class="links-of-blogroll-title">
{%- if theme.links_settings.icon %}<i class="{{ theme.links_settings.icon }} fa-fw"></i>{%- endif %}
{{ theme.links_settings.title }}
</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 %}

最后我们来看一下渲染出来的效果:

5.2.2 天气插件

接下来是一个天气的插件。我们这个插件来自tianqi.com,它这个可以实时获取城市,不过原来是直接使用的,现在要关注什么公众号了,不过我可以直接把代码给大家。这是我当时获取到的代码:

1
<iframe width="250" height="90" frameborder="0" scrolling="no" hspace="0" src="https://i.tianqi.com/?c=code&a=getcode&id=7&icon=1"></iframe>

目前还是可以正常运行的,不要求什么密码。我们还是找到site-overview.swig,把上面的代码粘贴到外链播放器下面去。看一下最终的效果:

5.3 不蒜子访客统计

需要一项服务来显示自己的客流量?Next中集成了busuanzi统计,虽然是第三方服务但也可以方便地添加到页面上。我们可以先看一下它的官网:

5.3.1 启用功能

当然我们不用那么复杂,又一次在swig添加那么多代码,我们只要找到对应的配置勾选一下:

1
2
3
4
5
6
7
8
9
10
# Show Views / Visitors of the website / page with busuanzi.
# Get more information on http://ibruce.info/2015/04/04/busuanzi
busuanzi_count:
enable: false
total_visitors: true
total_visitors_icon: fa fa-user
total_views: true
total_views_icon: fa fa-eye
post_views: true
post_views_icon: fa fa-eye

然后直接把所有的false改成true就可以拥有实时文章阅读量计数等功能。看一下最后的效果:

可是不对啊,我既然选了post_views,怎么不显示计数呢?于是我就去翻代码…

5.3.2 翻swig,瞎折腾

themes/next/layout/_macro/post.swig文件的120行找到这样的代码:

1
2
3
4
5
6
7
8
9
10
{%- if not is_index and theme.busuanzi_count.enable and theme.busuanzi_count.post_views %}
<span class="post-meta-item" title="{{ __('post.views') }}" id="busuanzi_container_page_pv"
style="display: none;">
<span class="post-meta-item-icon">
<i class="{{ theme.busuanzi_count.post_views_icon }}"></i>
</span>
<span class="post-meta-item-text">{{ __('post.views') + __('symbol.colon') }}</span>
<span id="busuanzi_value_page_pv"></span>
</span>
{%- endif %}

凭直觉来看,if not is_index很成问题啊!核理推测一下,是不是我们进入一篇文章就能看见post_views计数了?

果然。那在核理推测一下,是不是把not is_index and去掉,就可以在主页上显示了呢?我自己试了一下,发现这样会有bug,哪怕不看文章,也会出现计数的情况,个人没有想到特别好的解决方案,于是还是没有改。

5.4 相关文章插件

然后的话再讲一种引流的方式,这个相关文章插件。这算是一种站内引流吧。这个是最终的效果:

5.4.1 安装与配置

照常我们先找到对应的配置。然后看一下需要的dependency

1
2
3
4
5
6
7
8
9
10
11
12
# Related popular posts
# Dependencies: https://github.com/tea3/hexo-related-popular-posts
related_posts:
enable: false
title: # Custom header, leave empty to use the default one
display_in_home: false
params:
maxCount: 5
#PPMixingRate: 0.0
#isDate: false
#isImage: false
#isExcerpt: false

看起来我们需要安装hexo-related-popular-posts这个插件。安装过程中npm可能会提示你有部分package已被deprecated,不过不用管。安装后我们来改一下配置:

enable调成true之后就可以打开功能;display_in_home指要不要在主页上显示,我没开启;titlemaxCount什么的,我放张图就懂了(另及:isExcerpt要求文章中一定出现<!--more-->手动分页,默认不会显示全文):

所以最后的配置类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
# Related popular posts
# Dependencies: https://github.com/tea3/hexo-related-popular-posts
related_posts:
enable: true
title: 相关文章 为你推荐
display_in_home: false
params:
maxCount: 3
#PPMixingRate: 0.0
isDate: true
#isImage: false
isExcerpt: true

不过我们现在由于多方面原因(标签、分类等)并不会生成。我们随便再创一篇文章,来点相同的标签啥的。我们重新渲染…出错了!hexo g会出现两个ERROR,但没有更多信息,而hexo s运行后,有的文章打不开,还出现如下错误:

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
Unhandled rejection Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig) [Line 19, Column 14]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\_partials\head\head-unique.swig) [Line 10, Column 23]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig) [Line 3, Column 3]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\_partials\header\index.swig) [Line 6, Column 15]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\_partials\header\sub-menu.swig) [Line 2, Column 29]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\_partials\header\sub-menu.swig)
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig) [Line 5, Column 3]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\post.swig) [Line 9, Column 12]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\_macro\post.swig) [Line 214, Column 16]
Template render error: (D:\08 网站\hexo_website_tutorial\themes\next\layout\_partials\post\post-related.swig)
TypeError: config._d.getTime is not a function
at Object._prettifyError (D:\08 网站\hexo_website_tutorial\node_modules\nunjucks\src\lib.js:36:11)
at D:\08 网站\hexo_website_tutorial\node_modules\nunjucks\src\environment.js:563:19
at Template.root [as rootRenderFunc] (eval at _compile (D:\08 网站\hexo_website_tutorial\node_modules\nunjucks\src\environment.js:633:18), <anonymous>:45:3)
at Template.render (D:\08 网站\hexo_website_tutorial\node_modules\nunjucks\src\environment.js:552:10)
at D:\08 网站\hexo_website_tutorial\themes\next\scripts\renderer.js:32:29
at _View._compiled (D:\08 网站\hexo_website_tutorial\node_modules\hexo\lib\theme\view.js:136:50)
at _View.render (D:\08 网站\hexo_website_tutorial\node_modules\hexo\lib\theme\view.js:39:17)
at D:\08 网站\hexo_website_tutorial\node_modules\hexo\lib\hexo\index.js:64:21
at tryCatcher (D:\08 网站\hexo_website_tutorial\node_modules\bluebird\js\release\util.js:16:23)
at D:\08 网站\hexo_website_tutorial\node_modules\bluebird\js\release\method.js:15:34
at RouteStream._read (D:\08 网站\hexo_website_tutorial\node_modules\hexo\lib\hexo\router.js:47:5)
at Readable.read (node:internal/streams/readable:496:12)
at resume_ (node:internal/streams/readable:999:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

似乎是什么获取时间时有bug。有办法修复吗?

5.4.2 修复相关bug

经过多次尝试与搜索,我终于找到对应的解决方案。原文章参见“致谢”一节中的第5条。我们援引一下:

经过排查,本次发生错误是由 hexo-related-popular-posts 引发,在该库源码中使用 moment 初始化 list.date 导致了错误。 list.date 通过打印值可以看到是一个 moment 对象,但这个 moment 对象并不规范或者说可能在某处修改了这个 moment 对象的值。

moment 内部初始化有一段逻辑是:

1
this._d = new Date(config._d != null ? config._d.getTime() : NaN);

这个 config 就是 moment(list.date) 传入的 list.date 的值。config._d 是一个时间类型的字符串,并不是 Date 类型,因此没有 getTime 的方法。

临时解决方法有两种,一是将 isDate 设为 false,也就是推荐列表中不展示时间。

二是修改源码,做一层错误处理。从 node_modules 中打开文件(/node_modules/hexo-related-popular-posts/lib/list-json.js), 在编辑器中查找以下代码:

1
2
3
if (inOptions.isDate && list.date != '') {
ret.date = moment(list.date).format(config.date_format || 'YYYY-MM-DD')
}

修改为:

1
2
3
4
5
6
7
if (inOptions.isDate && list.date != '') {
try {
ret.date = moment(list.date).format(config.date_format || 'YYYY-MM-DD')
} catch(ex) {
ret.date = moment(list.date._d).format(config.date_format || 'YYYY-MM-DD')
}
}

上述只是临时的解决方案,由于不好确定是哪一方的原因,也不想继续耗费太多精力在上面。

我个人也不是特别了解原理,不过这的确解决了我们的问题。大概在这里:

然后便解决了。感谢anran758大佬。

5.5 评论系统

在写到这里的时候我有点犹豫,因为原来用的GiTalk由于某些网络原因(见下)挂掉了,又没有决定换什么,所以迟了好久。最后我选中的是来必力livere

《论我捣鼓GiTalk的简要过程》

写到这里我本想去截图,结果一看启动不起来,没办法新建issue也没法登录GitHub账号。在排查了设置、网络的问题后,我发现有个致命的问题:cors-anywhere.azm.workers.dev被墙掉,然后GiTalk无法进行GitHub oauth,就不能用了。

我于是尝试自己搭worker,结果发现是所有Cloudflare worker的链接都被墙掉了,然后我就彻底没招了,就只好作罢。不过……真的吗?

后来我找到了GiTalk的仓库,里面有类似的Issue,甚至翻出了CORS Anywhere的仓库,找到了一个基于Heroku的备用demo链接。在一个Issue某条评论某条评论中找到了一些备用链接。于是,就可以恢复正常了!

另及:今年(2022)11月28号Heroku会关闭所有的免费服务,所以你看到类似herokuapp.com的链接都不用试了…

最后的话成品是这样:

5.5.1 来必力livere

这个服务来自韩国,是韩语的页面,但是一旦应用到网站上就是中文的。到https://livere.com注册一个账号(你可能需要翻译),登录然后点击页首“安装”按钮,选择city版,填入链接什么的:

经过这一系列操作以后,我们会得到一串代码,在这里:http://livere.com/insight/myCode

复制data-uid里的内容,然后找到如下配置:

直接把你的data-uid复制进去就好了。看一下渲染的效果:

5.5.2 GiTalk

GiTalk的话是一个很“程序员”的评论系统。基于GitHub,支持Markdown,简单而优雅。不过,除了一些基本的配置以外,我们还需要更换CORS Anywhere的代理。我们先找到它的配置,看一下需要些什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Gitalk
# For more information: https://gitalk.github.io, https://github.com/gitalk/gitalk
gitalk:
enable: false
github_id: # GitHub repo owner
repo: # Repository name to store issues
client_id: # GitHub Application Client ID
client_secret: # GitHub Application Client Secret
admin_user: # GitHub repo owner and collaborators, only these guys can initialize gitHub issues
distraction_free_mode: true # Facebook-like distraction free mode
# Gitalk's display language depends on user's browser or system environment
# If you want everyone visiting your site to see a uniform language, you can set a force language value
# Available values: en | es-ES | fr | ru | zh-CN | zh-TW
language:

另外,这是人家的官网:

5.5.2.1 获取GitHub Application

大部分配置都好填,可是这个client_idclient_secret怎么办?我们需要自己新建一个GH App。打开https://github.com/settings/developers,并新建一个Oauth APP(右上角的按钮):

之后需要输入应用名称,应用官网(Homepage URLAuthorization callback URL),这两个一定一定要一样的,并且得加上https://

注册以后复制Client ID,新建Client secret,按红框里的按钮。

新建后务必立刻复制,否则就只能重新建了。

然后我们写到配置的client_idclient_secret里即可。至于其他的配置的话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Gitalk
# For more information: https://gitalk.github.io, https://github.com/gitalk/gitalk
gitalk:
enable: false
github_id: # GitHub repo owner
repo: # Repository name to store issues
client_id: # GitHub Application Client ID
client_secret: # GitHub Application Client Secret
admin_user: # GitHub repo owner and collaborators, only these guys can initialize gitHub issues
distraction_free_mode: true # Facebook-like distraction free mode
# Gitalk's display language depends on user's browser or system environment
# If you want everyone visiting your site to see a uniform language, you can set a force language value
# Available values: en | es-ES | fr | ru | zh-CN | zh-TW
language:

enable打开,github_id写上你的GitHub用户名,repo是你网站的仓库名(比如guleixibian2009.github.io),admin_user还是填自己的用户名。distraction_free_modelanguage自己按喜好调即可。

5.5.2.2 配置proxy

设置是好了,可是在用之前我们还需要改CORS Anywhere的镜像。我们如何把proxy改掉呢?参阅GiTalkREADME(见“致谢”,6),有一个proxy的选项。

我们找一下这个文件(themes/next/layout/_third-party/comments/gitalk.swig):

有这样一段代码。然后,把下面这段代码复制到里面去,如下:

1
proxy       : 'https://proxy.cors.sh/https://github.com/login/oauth/access_token'

最后的效果就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NexT.utils.loadComments(document.querySelector('#gitalk-container'), () => {
NexT.utils.getScript('{{ gitalk_js_uri }}', () => {
var gitalk = new Gitalk({
clientID : '{{ theme.gitalk.client_id }}',
clientSecret: '{{ theme.gitalk.client_secret }}',
repo : '{{ theme.gitalk.repo }}',
owner : '{{ theme.gitalk.github_id }}',
admin : ['{{ theme.gitalk.admin_user }}'],
id : '{{ gitalk_md5(page.path) }}',
{%- if theme.gitalk.language == '' %}
language: window.navigator.language || window.navigator.userLanguage,
{% else %}
language: '{{ theme.gitalk.language }}',
{%- endif %}
distractionFreeMode: {{ theme.gitalk.distraction_free_mode }},
proxy : 'https://proxy.cors.sh/https://github.com/login/oauth/access_token'
});
gitalk.render('gitalk-container');
}, window.Gitalk);
});

如果没看出来区别的话就直接复制替换即可。然后我们重新渲染,试一下:

不过如果需要尝试登录的话一定要部署之后才能测试…所以上线试一下登录:

然后GiTalk会自动创建一个Issue。我们应该可以在仓库里找到这样一个Issue,标题就是文章名:

如果一切正常的话,我们就配置成功了!

5.6 鼠标点击特效

当你点击页面时,你(之前是)可以看到一个彩色的爱心(的)。这个的话,先复制下面的代码:

1
!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);

然后在themes/next/source/js/src这个文件夹(自己创建)中,新建clicklove.js,代码复制进去即可。我们有了代码,但如何引用呢?我们需要找到模板文件(themes/next/layout/_layout.swig),并复制如下代码到这个位置:

1
2
<!-- 页面点击小红心 -->
<script type="text/javascript" src="js/src/clicklove.js"></script>

粘贴到这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  ...

{%- if theme.pjax %}
<div id="pjax">
{%- endif %}
{% include '_third-party/math/index.swig' %}
{% include '_third-party/quicklink.swig' %}

{{- next_inject('bodyEnd') }}
{%- if theme.pjax %}
</div>
{%- endif %}

<!-- 页面点击小红心 -->
<script type="text/javascript" src="js/src/clicklove.js"></script>
</body>
</html>

然后重新渲染试试:

然后现在我用的烟花的话,原理类似,新建一个fireworks.js,里面复制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
class Circle {
constructor({ origin, speed, color, angle, context }) {
this.origin = origin
this.position = { ...this.origin }
this.color = color
this.speed = speed
this.angle = angle
this.context = context
this.renderCount = 0
}

draw() {
this.context.fillStyle = this.color
this.context.beginPath()
this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
this.context.fill()
}

move() {
this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
this.renderCount++
}
}

class Boom {
constructor ({ origin, context, circleCount = 16, area }) {
this.origin = origin
this.context = context
this.circleCount = circleCount
this.area = area
this.stop = false
this.circles = []
}

randomArray(range) {
const length = range.length
const randomIndex = Math.floor(length * Math.random())
return range[randomIndex]
}

randomColor() {
const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
}

randomRange(start, end) {
return (end - start) * Math.random() + start
}

init() {
for(let i = 0; i < this.circleCount; i++) {
const circle = new Circle({
context: this.context,
origin: this.origin,
color: this.randomColor(),
angle: this.randomRange(Math.PI - 1, Math.PI + 1),
speed: this.randomRange(1, 6)
})
this.circles.push(circle)
}
}

move() {
this.circles.forEach((circle, index) => {
if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
return this.circles.splice(index, 1)
}
circle.move()
})
if (this.circles.length == 0) {
this.stop = true
}
}

draw() {
this.circles.forEach(circle => circle.draw())
}
}

class CursorSpecialEffects {
constructor() {
this.computerCanvas = document.createElement('canvas')
this.renderCanvas = document.createElement('canvas')

this.computerContext = this.computerCanvas.getContext('2d')
this.renderContext = this.renderCanvas.getContext('2d')

this.globalWidth = window.innerWidth
this.globalHeight = window.innerHeight

this.booms = []
this.running = false
}

handleMouseDown(e) {
const boom = new Boom({
origin: { x: e.clientX, y: e.clientY },
context: this.computerContext,
area: {
width: this.globalWidth,
height: this.globalHeight
}
})
boom.init()
this.booms.push(boom)
this.running || this.run()
}

handlePageHide() {
this.booms = []
this.running = false
}

init() {
const style = this.renderCanvas.style
style.position = 'fixed'
style.top = style.left = 0
style.zIndex = '999999999999999999999999999999999999999999'
style.pointerEvents = 'none'

style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight

document.body.append(this.renderCanvas)

window.addEventListener('mousedown', this.handleMouseDown.bind(this))
window.addEventListener('pagehide', this.handlePageHide.bind(this))
}

run() {
this.running = true
if (this.booms.length == 0) {
return this.running = false
}

requestAnimationFrame(this.run.bind(this))

this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)

this.booms.forEach((boom, index) => {
if (boom.stop) {
return this.booms.splice(index, 1)
}
boom.move()
boom.draw()
})
this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
}
}

const cursorSpecialEffects = new CursorSpecialEffects()
cursorSpecialEffects.init()

然后把_layout.swig里改一下就好了。效果的话,点击一下试试?

5.7 把猫…养在博客?

这一步也是很简单的啊。对对,我说的就是左下角那只白猫……

这个插件叫做live2d。官方地址的话,https://github.com/xiazeyu/live2d-widget-models/可以查到所有的model。这只猫的话,它叫tororo,虽然我也不知道为啥…我们需要先安装依赖:

1
npm install hexo-helper-live2d live2d-widget-model-tororo

但这样还不太行。我们需要加一段配置,加在Hexo_config.yml里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# live2d performance
live2d:
enable: true
scriptFrom: local
pluginRootPath: live2dw/
pluginJsPath: lib/
pluginModelPath: assets/
tagMode: false
debug: false
model:
use: live2d-widget-model-tororo
display:
position: left
width: 280
height: 560
mobile:
show: true

我并没有了解过所有的参数,反正就是把use改成live2d-widget-model-tororo,同时改一下位置、长、宽即可。

嘿嘿,看起来这一段很短,对吧?其实我当时研究了很久,网上没有太好的教程,最后才发现要安装hexo-helper-live2d啊。

5.8 AddThis Utilities分享功能

虽然我这个博客还是没什么名气,可万一之后需要有一个分享功能,怎么办?在Next的配置中提到了Addthis分享。这个怎么实现呢?

先到addthis.com注册一个账号(另及:加速Google Recaptcha的方法见之后的文章),然后照着这些截图来:

登录之后有这样一个页面,我们选择第一个,Share Buttons

然后,选择Floating

之后我们开始自定义工具。先选择Selected by you,用ADD MORE SERVICES改分享方式;

最后我选了这些,比如微信、QQ、生成二维码等等;

在第四个栏目里调整一下位置,和手机是否显示;

最后Activate Tool,获取代码;

不过我们不需要所有的代码,找一下代码里的pubid,应该是ra-打头,接着复制进配置文件里即可。

渲染看一下。

另及:如果没有的话,检查一下是否浏览器屏蔽了“跟踪器”。

还有…我本来想继续写下去,写一个Widgetpack打分功能。可惜人家服务器有问题,功能暂时下线了,等恢复了我再加上吧。

好耶!我们现在就把这8个功能配置完啦!接下来…我们来看一点更高级的东东!


6. 更高级的功能

这一章的话,主要讲一些“看不见”的东西,比如站点地图,RSS等等。

6.1 RSS订阅

一般博客都是提供RSS Feed来订阅的。之前我们提到过RSS,包括侧边栏链接、文章结尾的友链,等等。要生成的话我们只需要安装插件hexo-generator-feed,每次hexo g都会自动生成。

1
npm install hexo-generator-feed --save

不过,生成出来的文件在哪里呢?看一下…应该是/atom.xml

6.2 站点地图sitemap

站点地图的话主要是为搜索引擎用的,这一小节算是给后文的一个铺垫。同样的,只需要安装插件hexo-generator-sitemap即可。这次生成出来的是/sitemap.xml

6.3 CDN与图床

默认的话,next会使用jsdelivr作为默认的CDN,不过cdn.jsdelivr.net这个节点不是特别的稳定(被墙过),所以我个人是换到了fastly节点上。具体位置的话,在这里,至于改不改就看你自己了。

同时如果你想要往文章里添加图片,那光靠自己的域名(也就是GitHub)肯定是不够的,我们一定会需要一个快速的、稳定的图床。我个人推荐是imgse路过图床,它这个是免费的,而且已经有10年历史,上传也非常方便。它支持10MB内的JPGPNG,子节点是ax1x.com

6.4 Bing SEO

搜索引擎优化确实是一件很重要的事情,最简单的是Bing。官网的话,https://www.bing.com/webmasters/about/,用Microsoft账户登录是最方便的(除非你有FB或者Google,不过这不太可能吧)。

6.4.1 注册与验证

登录进来之后,我们输入网址,登记页面(页面布局可能和图片有些许区别)。

登记过后会要求我们验证页面。三种方法中最简单的是<meta>标签,直接复制代码,然后加到_layout.swig<head>里去就好了。重新渲染、部署,然后等待片刻、验证。

这就代表验证成功了。

6.4.2 提交网站地图

点击右上角那个“提交站点地图”,并输入你刚生成的站点地图的网址,可以加速爬网。

然后…等待扫描…可能会需要一段时间。

这就代表扫描完了:

不过真正能搜到是需要2天时间的,先放一下我自己的博客的截图:

当然这个SEO肯定是不止这么多的。相关的功能等着你去探索,包括Microsoft Clarity等等。

6.5 模板文件与动态样式表

最后这一小节不是具体的教你去“干什么”,而是具体“怎么干”。每个人对网站的外观跟行为逻辑有自己的看法,而自定义的终极方式就是修改底层。

Next这个主题下,关于底层的两个文件夹,一个是layout,一个是source,具体见下:

6.5.1 Mozilla Nunjucks

在上网查之前我一直以为我们修改的什么_layout.swig啊都是用什么swig语言写的,但一搜其实并没有这个语言(有,但极其小众,且已为unmaintained状态)。直到我看到renderer.js里的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* global hexo */

'use strict';

const nunjucks = require('nunjucks');
const path = require('path');

...

// Return a compiled renderer.
njkRenderer.compile = function(data) {
const compiledTemplate = njkCompile(data);
// Need a closure to keep the compiled template.
return function(locals) {
return compiledTemplate.render(locals);
};
};

hexo.extend.renderer.register('njk', 'html', njkRenderer);
hexo.extend.renderer.register('swig', 'html', njkRenderer);

才发现有nunjucks这种语言。它的语法可以在官网https://mozilla.github.io/nunjucks/查到,据说和jinja2(基于Python的)一模一样,此外还支持自定义后缀什么的。这里讲一点特殊的变量,举些例子:

1
2
3
4
5
6
7
8
9
10
{%- if theme.pjax %}
<div id="pjax">
{%- endif %}
{% include '_third-party/math/index.swig' %}
{% include '_third-party/quicklink.swig' %}

{{- next_inject('bodyEnd') }}
{%- if theme.pjax %}
</div>
{%- endif %}

(来自_layout.swig)有一个if语句,后面跟的是theme.pjax。这个theme指的是Next主题的_config.yml

1
2
3
4
5
6
7
8
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
{%- if theme.avatar.url %}
<img class="site-author-image" itemprop="image" alt="{{ author }}"
src="{{ url_for(theme.avatar.url) }}">
{%- endif %}
<p class="site-author-name" itemprop="name">{{ author }}</p>
<div class="site-description" itemprop="description">{{ description }}</div>
</div>

(来自_partials/sidebar/site-overview.swig)这里引用了一个变量{{ author }},像这种没有theme.的都来自Hexo_config.yml

1
{% block title %}{{ page.title }} | {{ title }}{% endblock %}

(来自post.swig)这里引用的{{ page.title }}有前缀page.,代表当前正渲染的页面(准确地说是postpageFront Matter)。

6.5.2 Stylus

这个就没太多好讲的了,因为我自己也没学过动态CSS。在source/css这个文件夹下所有.styl后缀的文件都是样式表。我们之前修改过一个书签的,还记得吗?


7. 总结与回顾

到这里,我们所有的教程已经写完了。在这“短暂的”几十分钟,几小时,甚至几天中,我们终于成功的做出来这样一个基于Hexo+Next的博客网站了。还记得那几条命令吧,我还是写在这里备用。

  • hexo clean清除本地缓存

  • hexo g生成网页

  • hexo s打开本地服务器

  • hexo d部署到远程

  • hexo new新建文章

  • hexo new page新建页面

接下来,就是你继续探索,大展身手的时刻了!嗯…48k字,我也是圆了长久以来的梦想。那么,我们就下次再见喽~


8. 致谢

这里写一下我参考到的文章:

  1. 基于Github.io+Hexo搭建个人博客 | JerryMiao2019’s Blog

  2. 解决hexo-renderer-kramed渲染冲突的部分问题 | 卡洛的核心舱

  3. Hexo+Next主题优化 | 知乎

  4. Hexo博客优化之Next主题美化 | nightmare_dimple的博客 | CSDN博客

  5. Hexo 常见问题解决方案 | Anran758’s blog

  6. GitHub - gitalk/gitalk

  7. Hexo给NexT主题内添加页面点击出现爱心的效果_| 女王的禅师范的博客 | CSDN博客

  8. Hexo-NexT 添加打字特效、鼠标点击特效 | 小丁的个人博客

  9. Hexo+yilia添加helper-live2d插件宠物动画,很好玩的哦~~ | 王约翰 | 博客园

  10. Github 搭建 hexo (五)- 站点地图(sitemap.xml)|_Small蒙奇的博客 | CSDN博客

THE END感谢您的阅读~

赏作者一杯作业......