接上篇,由于技术有限,上篇做了分类归档页面有严重的 BUG,经过很久的分析也没解决这个问题。经过大量的查找资料和官方文档,甚至还读了 Hexo 的源码,发现到 Hexo 自带的 list_categories 辅助函数也许能解决我的问题。遂开此篇通过编写插件注册一个自定义辅助函数,最终也随愿解决了这个问题。

本文不贴整套的源码,只粗略的贴局部代码解决这个问题,不过贴出的源码已经是解决这个问题的全部代码。认真读文章!

自定义插件

很多人不理解为什么要有插件,因为我们已经被浏览器的插件烦透了对吗? 没错。不受控的插件只会把用户搞疯狂,但是受控的插件,可以锦上添花。插件存在的意义是,一定要解决用户痛点。本节实例只会打印一句log,很显然没人会用这个插件。

新建package.json文件

在你的hexo blog目录,找到node_modules. 新建一个文件夹。然后执行npm init
npm会引导你生成package.json 这是你的包的描述文件。需要注意的是,所有的hexo插件必须以hexo-开头,否则hexo不会加载。

1
2
3
4
5
6
7
8
9
npm install hexo-cli -g
hexo init blog
cd blog
npm install //这4步如果已有无需再敲

cd node_modules
mkdir hexo-umatobu-category //名字你随意定义,必须 hexo- 开头
cd hexo-umatobu-category
npm init

根据提示输入信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ npm init
...
package name: (hexo-umatobu-category) hexo-umatobu-category
version: (1.0.0) 0.0.1
description: A detailed list of categories of hexo
entry point: (index.js)
test command:
git repository:
keywords: hexo umatobu category
author: umatobu
license: (ISC) MIT

Is this OK? (yes)

回车然后package.json 就生成好了。

新建index.js文件

根据上面的package.json, 我们设置了入口JS文件名,因此必须新建一个index.js,这个包才完整。
我们根据hexo文档,注册插件,这个插件会在hexo 生成静态文件时,打印一条log.

1
2
3
hexo.extend.filter.register('before_generate', function(){
console.log("111111111111111111111111");
});

测试

回到上级目录,修改hexo的 package.json,新增一行到dependency:

1
"hexo-umatobu-category": "^0.0.1"

然后,每次执行hexo g或者hexo s, 都会看到插件的log, 证明插件已经运行了。

辅助函数

通过查询 Hexo 文档我们发现辅助函数中有个 list_categories 可以制作分类列表,但是这个不符合我想要的效果(我想要必须两级分类,且分类下面有对应的文章列表)。通过上篇教程我们进行了很多的尝试结果都不能达到预期效果,怎么办呢?我想到了一个方法,既然 list_categories 的列表是可以展示全部的列表(多级不会丢失分类),那么我们为什么不去看看 list_categories 的源码去定制一个自己的 list_categories 呢?

首先我们找到 Hexo 在 GitHub 托管的源码地址,我在 lib/plugins/helper/ 目录下找到了 list_categories.js 文件,通过略读我发现这个就是 list_categories 辅助函数的源码。

经过上节的学习我们已经知道了怎么编写插件,那么我们把上节的 index.js 文件内容改为这样:

1
2
3
hexo.extend.helper.register('my_list_categories', function(categories){
return `<h1>Hello World!</h1>`;
});

然后将 archive.ejs 里面使用的 list_categories 辅助函数 替换为 my_list_categories,再次开启服务,转到归档页面,你会惊奇的发现竟然出现了一个内容为 “Hello World!” 的 h1 标签~

那么接下来,我通过慢慢钻研 Hexo 的 list_categories 源码,写出这样一个自定义的辅助函数:

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
hexo.extend.helper.register('my_list_categories', function(categories){

if (!categories || !categories.length) return '';

const prepareQuery = parent => {
const query = {};

if (parent) {
query.parent = parent;
} else {
query.parent = {$exists: false};
}

return categories.find(query).sort('name', 1).filter(cat => cat.length);
};

const hierarchicalList = (level, parent) => {

if(level > 1) return '';
let result = '';

prepareQuery(parent).forEach((cat, i) => {

let child;
child = hierarchicalList(level + 1, cat._id);

if (child) {
result += `<h2 class="archive-main-category">${cat.name}</h2>`;
} else {
result += `<div class="subtitle-item"><div class="subtitle-info">${cat.name}</div></div>`;

//sort by date
var posts = {};
for(var n = 0; n < cat.posts.length; n++)
{
var post1 = cat.posts.data[n];
var date1 = this.date(post1.date, "YYYY-MM-DD hh:mm:ss") + post1.title;
posts[date1] = post1;
}
function objKeySort(obj) {
var newkey = Object.keys(obj).sort();
var newObj = {};
for (var i = 0; i < newkey.length; i++) {
newObj[newkey[i]] = obj[newkey[i]];
}
return newObj;
}
posts = objKeySort(posts)
var posts_keys = Object.keys(posts);

for(var k = 0; k < posts_keys.length; k++)
{
var post2 = posts[posts_keys[k]];
result += `<div class="post-item">`;
result += `<div class="post-info">${this.date(post2.date, "YYYY-MM-DD")}</div>`;
result += `<a href="${this.url_for(post2.path)}" class="post-title-link" target="_blank">`;
result += `${post2.title}</a></div>`;

if(k == (cat.posts.length-1))
{
result += `<p> </p>`;
}
}
}

if (child) {
result += `${child}`;
}
});

return result;
};

return `<ul class="post-archive">${hierarchicalList(0)}</ul>`;

});

测试

分类归档展示图