这是hexo主题系列文章的第四篇,继续加油。
1.关于文章时间的问题 今天打开网站一看,发现了每篇文章的创建时间都有些问题,以前一直没有注意。
这里都写得是凌晨,我明明没有那么努力的。后来发现,在网站的_config.yml中,没有写时区,添加上timezone: Asia/Shanghai。
结果还是没解决问题,继续探究,后来我又查看了模板文件,原来是因为我显示时间的时候,用的是12小时而不是二十四小时,将模板文件中显示时间的地方由:moment(post.date).format(“YYYY-MM-DD hh:mm:ss”),改为:moment(post.date).format(“YYYY-MM-DD HH:mm:ss”)。
这下结果就对了。
2.使用hexo-renderer-marked渲染md字符串 先说下需求,主要是这样的。我通过hexo新建了一个html页面,将layout修改为自定义的内容,如果正常情况下,全部的html会经过hexo的渲染,生成html,但是我想如果页面中存在style和script标签,就将style提取到页面的头部,将script放到页面的底部,而不是被hexo的markdown直接将sytle和script放到了body里面,除了这两个内容,剩下的内容继续由markdown渲染器进行渲染。通过查看hexo-renderer-marked我发现它是调用了marked这么一个markdown渲染器,然后进行了相应的扩展,那这就好办了,因为安装hexo时已经安装了hexo-renderer-marked和mrked这两个库,直接用就好了。
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 var cheerio = require ('cheerio' );var hexomarked=require ('./renderer' );var path=require ("path" );var rendererFormat=".html,.md,.markdown,.mkd,.mkdn,.mdwn,.mdtxt,.mdtext" ;hexo.extend .filter .register ('before_post_render' ,function (data ){ let content=data.content ; if (data.layout !="post" ){ data.scripts =[]; data.styles =[]; var $ = cheerio.load (content, { ignoreWhitespace : false , xmlMode : false , lowerCaseTags : false , decodeEntities : false }); $('style' ).each (function (index,item ){ var text=$(this ).html ().trim (); $(this ).remove (); data.styles .push (text.replace (/[\r\n]/g ,"" )); }) $('script' ).each (function (index,item ){ var text=$(this ).html ().trim (); $(this ).remove (); data.scripts .push (text.replace (/[\r\n]/g ,"" )); }) content=$.html (); var extname=path.extname (data.path ); if (rendererFormat.indexOf (extname)>=0 ){ content=hexomarked (content); } data.content =content; return data; } });
其中的hexomarked其实是hexo在marked的基础上实现的自定义的渲染方式,我只是把放到node_modules/hexo-renderer-marked/lib/renderer.js中的文件复制到了我主题下的script文件夹下,(不直接是使用hexo-renderer-marked的原因,也是因为我只想用renderer而不想用其他的代码)这样在生成文章的时候就会自动执行我写的代码了。
后来在hexo从3.x升级到4.x的过程中,出现了:Class constructor Renderer cannot be invoked without ‘new’ 的错误。
主要原因是4.x版本中,所有的类使用了es6的语法,所以apply就不可以使用了。
1 2 3 4 5 6 7 8 9 10 11 function Renderer ( ) { MarkedRenderer .apply (this ); this ._headingId = {}; } class Renderer extends MarkedRenderer {}
3.奇怪的标签页 (1) 我在文章中,写了两篇关于Avro的文章,我把标签修改为Avro
奇怪就奇怪在,运行 hexo g 后生成的tags/index.html中竟然出现了错误的html,明显html已经结束了,但是还是又出现了重复的html结束标签。
当我把这篇文章的这个tag标签,改为小写,结果就渲染成了正确的html。
(2) 仔细查看有些文章标签页总是少一个,比如我又三篇文章的tag是avro,但是显示出来的index页中却却缺少一项内容,而且使用的模板并不是我的tag.swig模板(通过修改模板查看得出结论)
(3) 临时解决方案:
将source/tags/index.md中添加:type: tags
同理新建categories页面
1 2 hexo new page categories
修改source/categories/index.md中添加:type: categories
5.代码调整生成tag标签的方式 需求是这样的,写文章很多,标签就很多,有时候同一个标签只是因为是大小写不同,就被分成了不同的标签,但是我想总会有写错的时候,就统一标签,将标签的第一个字母大写,这样就算是不小心写错了大小写,也会归为同一类标签下。通过参考hexo-generator-tag的源码方式,我发现了,通过在generator生成器中通过定义返回一个数组,就可以生成多个文件夹。代码如下:
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 var pagination = require ('hexo-pagination' );var _=require ("lodash" )hexo.extend .generator .register ('tag' , function (locals ){ let tagsPage={} locals.posts .map (function (post ){ var tags=post.tags .data ; for (let menuItem in tags){ let name=tags[menuItem].name ; name=name.toLowerCase ().replace (/( |^)[a-z]/g , (L ) => L.toUpperCase ()); tags[menuItem].name =name; if (!tagsPage[name]){ tagsPage[name]=[]; } tagsPage[name].push (post); } }); let themeConfig=hexo.theme .config ; let perPage=(themeConfig.tag_generator &&themeConfig.tag_generator .per_page )?themeConfig.tag_generator .per_page :10 ; var pages=[]; for (let tageName in tagsPage){ let page=tagsPage[tageName]; var data = pagination ("/tags/" +tageName.replace (/\.|\s/g ,"_" ), page, { perPage : perPage, layout : ['tag' , 'index' ], format : 'tags/%d/' , data : { tag : tageName, total :page.length } }); pages=[...pages,...data]; } return pages; });
生成分类的时候,就用:
1 hexo.extend .generator .register ('category' )
6.最终页面上的标签生成策略 生成标签云的思路就是,使用nodejs读取source/_posts目录下的所有md文件,使用gray-matter,解析文件标头,然后生成标签的数组,然后在页面上使用新的变量newTags,最后配合自定义生成标签的路由hexo.extend.generator.register(‘tag’)函数,最终形成了自己的标签云以及对应的路由。
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 var _uniqBy=require ("lodash/uniqBy" );var fs=require ("fs" );var path = require ('path' );var grey_matter=require ("gray-matter" );var _=require ("lodash" );var rendererFormat=".html,.md,.markdown,.mkd,.mkdn,.mdwn,.mdtxt,.mdtext" ;function travel (dir, callback ) { fs.readdirSync (dir).forEach (function (file ) { var pathname = path.join (dir, file); if (fs.statSync (pathname).isDirectory ()) { travel (pathname, callback); } else { callback (pathname); } }); } var postTags=[];var source=hexo.source .base ;travel (path.resolve (__dirname, source+'/_posts' ),function (filePath ){ var extname=path.extname (filePath); if (rendererFormat.indexOf (extname)>=0 ){ try { var data=fs.readFileSync (filePath,{ encoding : 'utf-8' }); var obj=grey_matter (data); var titleObj=obj.data ; var tags=titleObj.tags ; if (tags){ if (_.isArray (tags)){ postTags=_.merge (tags,postTags); }else { postTags.push (tags); } } }catch (err){ console .log (err); } } }); postTags=_.uniq (postTags); postTags=_.map (postTags,function (item ){ return _.capitalize (item); }); hexo.extend .filter .register ('template_locals' , function (locals ){ let menuArray=[]; let categories=hexo.locals .get ("categories" ).data ; let categoriesName=[]; for (let menuItem in categories){ let name=categories[menuItem].name ; name=name.toLowerCase ().replace (/( |^)[a-z]/g , (L ) => L.toUpperCase ()); if (categoriesName.indexOf (name)<0 &&name!=null &&name!="" ){ menuArray.push ({"name" :name,"path" :"/categories/" +name.replace (/\.|\s/g ,"_" )+"/" }); } } menuArray=_uniqBy (menuArray,"name" ); locals.headermenu =menuArray; let tags=hexo.locals .get ("tags" ).data ; let newTags=[]; for (let menuItem in tags){ let name=tags[menuItem].name ; name=name.toLowerCase ().replace (/( |^)[a-z]/g , (L ) => L.toUpperCase ()); if (postTags.indexOf (name)>=0 &&name!=null &&name!="" ){ tags[menuItem].name =name; tags[menuItem].path ="/tags/" +name.replace (/\.|\s/g ,"_" )+"/" ; newTags.push (tags[menuItem]); } } locals.newTags =newTags; return locals; });
期间主要使用了lodash函数,nodejs的readFile函数,以及插件gray-matter。
7.生成文章的摘要 如果没有在more上面写东西的话,文章是没有摘要的,那么如何自动生成摘要呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var cheerio = require ('cheerio' );hexo.extend .filter .register ('after_post_render' , function (data ){ if (!data.excerpt ||data.excerpt =="" ){ var $ = cheerio.load (data.more , { ignoreWhitespace : false , xmlMode : false , lowerCaseTags : false , decodeEntities : false }); var text=$("p" ).text (); data.excerpt =text.substring (0 ,250 ); } return data; });
8.执行hexo clean 无法清理缓存 这个问题一直让我很头大,明明已经修改了after_post_render函数,但是就是应用不上去,比如上面的代码,data.excerpt这个,在页面上还是显示为空,即使你把data.content设置为空,还是渲染了以前的内容。这就比较尴尬了。我丧心病狂的都重启计算机了,才终于看到效果改变了。 其实如果hexo clean不起作用,就直接把hexo目录下的db.json直接删除就好了。这样就算删除了缓存了。