本次对Hexo的修改,主要完成如下两个功能:
- 第一,Hexo的分类默认使用名称按照字典排序,我希望是自己可以方便指定分类序号,从而按序号排序显示;
 
- 第二,Hexo的分类名称需要直接写在Post文档categories的字段,后续如果需要修改某个分类名称,需要修改多个文档,我希望是给每个分类起个别名,Post文档中使用该别名,在特定的文档中定义别名和真实名称的映射关系,然后Hexo生成静态页面时,Hexo自动对别名进行替换。
 

0x00 实现步骤
- 第一,在博客项目的根目录创建文件categories.json,文件中定义别名和真实名称的映射关系;
 
- 第二,自己创建创建一个模块,该模块中完成categories.json读取、别名到真实名称的转换以及分类排序等三个功能。并将该模块发布到npmjs.org;
 
- 第三,修改node_modules\hexo\dist\plugins\helper\list_categories.js中的listCategoriesHelper函数,使用我们上述自定义的分类函数,来生成静态文件。
 
- 第四,修改themes\next\layout_macro\sidebar.swig 和 themes\next\layout_macro\post.swig,完成别名到真实名称的转换;
 
0x01 第一步:创建文件categories.json
在项目根目录创建映射文件:

我们以当前博客网站的分类作为演示,其内容如下:

0x02 第二步:实现自己的函数,并定义为新的模块
我给这个模块起了名字叫做 hexo-mancode,该模块的文件index.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
   | fs = require('fs');
  global.pages_mancode = {};
 
  hexo.extend.filter.register('before_generate', function(){ 	this.log.info("hexo_mancode: before_generate ****");
  	global.pages_mancode = JSON.parse(fs.readFileSync("./categories.json", "utf8")); });
 
  hexo.extend.helper.register('my_list_categories', function(catname){ 	var item = global.pages_mancode.categories.find(item => { return item.cat == catname; } );
  	return (item == undefined)?"没有分类":item.name; });
 
  hexo.extend.helper.register('my_list_sortfunc', function() { 	return (av, bv) => { 		var as = global.pages_mancode.categories.find(item => { return item.cat == av.name; } ); 		var bs = global.pages_mancode.categories.find(item => { return item.cat == bv.name; } );
  		if      (as == undefined && bs == undefined) 		{ 			return av.name  < bv.name ?-1:(av.name  > bv.name ?1:0); 		} 		else if (as != undefined && bs != undefined) 		{ 			return as.order < bs.order?-1:(as.order > bs.order?1:0); 		} 		else if (as == undefined) 		{ 			return 1; 		} 		else if (bs == undefined) 		{ 			return -1; 		} 	} });
  | 
 
文件创建完毕之后,将该模块发布到npmjs.org,发布模块的具体方法请参考当前博客的其他文章。

修改package.json文件,增加对hexo-mancode的依赖和自动下载。
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
   | {   "name": "hexo-site",   "version": "0.0.0",   "private": true,   "scripts": {     "build": "hexo generate",     "clean": "hexo clean",     "deploy": "hexo deploy",     "server": "hexo server"   },   "hexo": {     "version": "7.3.0"   },   "dependencies": {     "hexo": "^7.3.0",     "hexo-generator-archive": "^2.0.0",     "hexo-generator-category": "^2.0.0",     "hexo-generator-index": "^4.0.0",     "hexo-generator-tag": "^2.0.0",     "hexo-renderer-ejs": "^2.0.0",     "hexo-renderer-marked": "^6.3.0",     "hexo-renderer-stylus": "^3.0.1",     "hexo-server": "^3.0.0",     "hexo-theme-landscape": "^1.0.0",     "hexo-mancode": "^1.0.0"   } }
  | 
 
0x03 第三步:修改模块hexo的list_categories.js函数
node_modules\hexo\dist\plugins\helper\list_categories.js文件的位置,如下图所示:

修改后的文件内容(修改前的list_categories.js,修改后的list_categories.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
   | "use strict"; const hexo_util_1 = require("hexo-util"); function listCategoriesHelper(categories, options) {     if (!options && (!categories || !Object.prototype.hasOwnProperty.call(categories, 'length'))) {         options = categories;         categories = this.site.categories;     }     categories = categories;     if (!categories || !categories.length)         return '';     options = options || {};     const { style = 'list', transform, separator = ', ', suffix = '', mysort } = options;     const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') ? options.show_count : true;     const className = options.class || 'category';     const depth = options.depth ? parseInt(String(options.depth), 10) : 0;     const orderby = options.orderby || 'name';     const order = options.order || 1;     const showCurrent = options.show_current || false;     const childrenIndicator = Object.prototype.hasOwnProperty.call(options, 'children_indicator') ? options.children_indicator : false;     const prepareQuery = parent => {         const query = {};         if (parent) {             query.parent = parent;         }         else {             query.parent = { $exists: false };         }         return categories.find(query).sort(orderby, order);     };               const myhtml = () => {         let mhtml = "";         var sortBy = mysort?mysort():(a, b)=>{ return (a.name < b.name)?-1:(a.name>b.name?1:0); };	 		    categories.data.sort(sortBy).forEach((cat) => {             mhtml += `<li class="${className}-list-item">`;             mhtml += `<a class="${className}-list-link" href="${hexo_util_1.url_for.call(this, cat.path)}${suffix}">`;             mhtml += transform ? transform(cat.name) : cat.name;             mhtml += '</a>';
              mhtml += `<span class="${className}-list-count">${cat.length}</span>`;
              mhtml += '</li>';             }); 		                 return mhtml;     }
      const hierarchicalList = (level, parent) => {         let result = ''; 		         prepareQuery(parent).forEach((cat) => { 	             let child;             if (!depth || level + 1 < depth) {                 child = hierarchicalList(level + 1, cat._id);             }             let isCurrent = false;             if (showCurrent && this.page) {                 for (let j = 0; j < cat.length; j++) {                     const post = cat.posts.data[j];                     if (post && post._id === this.page._id) {                         isCurrent = true;                         break;                     }                 }                                  isCurrent = isCurrent || (this.page.base && this.page.base.startsWith(cat.path));             }             const additionalClassName = child && childrenIndicator ? ` ${childrenIndicator}` : '';             result += `<li class="${className}-list-item${additionalClassName}">`;             result += `<a class="${className}-list-link${isCurrent ? ' current' : ''}" href="${hexo_util_1.url_for.call(this, cat.path)}${suffix}">`;             result += transform ? transform(cat.name) : cat.name;             result += '</a>';             if (showCount) {                 result += `<span class="${className}-list-count">${cat.length}</span>`;             }             if (child) {                 result += `<ul class="${className}-list-child">${child}</ul>`;             }             result += '</li>';         });         return result;     }; 	     const flatList = (level, parent) => {         let result = '';         prepareQuery(parent).forEach((cat, i) => {             if (i || level)                 result += separator;             result += `<a class="${className}-link" href="${hexo_util_1.url_for.call(this, cat.path)}${suffix}">`;             result += transform ? transform(cat.name) : cat.name;             if (showCount) {                 result += `<span class="${className}-count">${cat.length}</span>`;             }             result += '</a>';             if (!depth || level + 1 < depth) {                 result += flatList(level + 1, cat._id);             }         });         return result;     };     if (style === 'list') {          		         return `<ul class="${className}-list">${myhtml()}</ul>`;     }     return flatList(0); } module.exports = listCategoriesHelper;
   | 
 
themes\next\layout_macro\sidebar.swig文件修改如下:

themes\next\layout_macro\post.swig文件修改如下:

0x05 第五步:使用方法
第一:如果重新安装模块,也就是重建node_modules文件夹,需要在执行 npm install 之后,手动修改 list_categories.js 文件。
第二:如果新增加分类或者调整分类的排序,需要调整categories.json中内容。
第三:post文档指定分类别名的方法,如下图所示:

0x06 参考资料