Hexo 自定义主题
从这一篇文章开始,我想基于Hexo的Next主题自己写,打造一个个性化的博客。一点点的尝试吧,搞不好,总可以搞坏的。
将Next主题从网上下载下来,放到hexo网站的themes文件夹下,并命名next,修改网站_config, 将theme,改为theme:next。运行命令hexo s,打开浏览器localhost:4000查看效果。我自己定义的主题,大多借鉴Next主题。Next主题主要使用了node-swig作为hexo的模板,要想好好的看懂Next,需要知道简单的语法规则:学习链接 (刚发现swig好像不维护了,哎,还没学会,就被淘汰了。nunjucks好像语法差不多和siwg: api ) ,而且hexo最新版本也换成了nunjucks,我觉得语法差不多,就是换一个文件后缀名的问题,但是也不排除有不一样的行为, Next使用的css模板是Stylus模板( stylus-lang.com )
1.根据设置生成CSS,这里有个地方注意下“hexo提供了hexo-config方法,可以读取_config.yml中的配置”,所以你可以在styl文件中经常看到这个函数,你要单独搜这个东西,好像还真是不明显。
2.在js插件中访问设置,在js插件中访问设置
1.修改网站标题和作者
打开hexo的_config.yaml配置文件,不是主题的配置文件,开头几行就是。title,subtitle,author.
## 2、选择Next主题的风格
Next主题包含了四种风格,分别是Muse、Mist、Pisces、Gemini,将需要的主题前面的#号去掉,不需要的主题使用#注释掉。
3.自定义主题
主要解决的问题是:
3.1.熟悉主题的结构
--+themes
-----+themename
--------+languages //国际化语言,在swig文件中,通过__(变量名)调用,变量名极为zh-CN.yml中的变量名
-----------+zh-CN.yml //
-----------+en.yml
-----------+.......
--------+layout //布局页面,相当于html
-----------+index.swig //首页的模板
-----------+post.swig //文章的模板
-----------+page.swig //new page 模板
-----------+category.swig //归档页模板
-----------+tag.swig //标签页模板
-----------+。。。。。 //可以添加其他的模板或文件夹,便于相互之间使用swig语法引用
---------+scripts //hexo会在生成页面时(即执行hexo g命令时)自动调用scripts文件夹下的js文件,可以写些js做些自动化
---------+source //主题的资源文件夹
-----------+js //主题的js代码所在位置
-----------+css //主题的css所在位置
-----------+images //主题的图片所在位置
-----------+fonts //主题的字体位置
-----------+。。。。 //其他文件或文件夹,方便相互引用
hexo在生成静态文件时,会自动寻找layout中的index.swig文件,生成首页,然后找到post.swig,根据post.swig生成文章页面,同理,page.swig就是使用“hexo new page ‘new page’”命令时产生的page页面的模板。swig文件可以相互引用,在index.swig中可以使用其他的swig文件,也可以自定义,在swig文件中可以使用hexo的辅助函数和变量。在swig文件中使用的图片和js脚本通常放到source文件夹中,在swig可以直接通过引入script标签引入js,或者是css文件,其中js即为source文件夹下的js文件夹,lib即为source文件夹下的lib,在生成页面时,hexo会自动处理复制。
1 | //引入css文件 |
source下的css文件夹存放hexo可能会用到的css文件,再css这一级的更目录下可以自由添加任何css文件,hexo在生成文章时会自动将文件复制到public/css文件夹中,添加的styl类型文件会被编译后复制到public/css文件夹中,文件或文件夹名称带下滑线,不会自动复制,引用时可以在styl文件中通过@import引入,hexo就可以自动处理了。
hexo默认会生成tags(标签目录)、categories(分类目录)、archives(归档目录),查看生成的public目录即可。每一个目录下都有一个index.html页面,是根据tag.swig、category.swig模板生成的,没有定义相应的模板,就用默认的index.swig模板生成。
3.2.熟悉swig语法
生成文章时的执行顺序如下:
1 | 执行 before_post_render 过滤器 |
swig文件没有了,可以使用Nunjucks渲染,模板语法 ,官网
3.3.活用hexo辅助函数和变量
3.4.主页中如何进行分页
首页(index),变量为page,我觉得这个page不仅仅代表着首页,也代表着每一个目录页,tag、categories。
3.5.自定义菜单栏
这里解决的一个主要问题我觉得要明白如何进行分页,例如新建一个菜单项,打开这个菜单项时,出现和首页一样的分页效果。这里有参考资料, 主要思想就是用归档页代替page页,因为hexo的归档页(category)和标签页(tag)是支持分页的,也就是可以在category.swig和tag.swig中使用page.posts,在主配置文件中也有index_generator,和default_category支持配置归档页和标签页每页显示的文章数,根据这个思路,那么菜单栏,每一项要支持分页,菜单栏的路径就应该指向一个归档目录,例如:catetories/随笔
3.6.关于国际化
现在看起来好像是在生成页面以前,就进行了一个merger,在next主题文件夹的scripts文件夹下,但是他执行的原理和方法,还没有详细研究,等有机会再说吧。
3.7在首页上添加了一个缩略图的效果
实现的原理就是通过在主题文件家下新建一个文件夹scripts,将js文件写到里面,hexo生成文章的时候会自动执行这里面的js文件。我自定义了一个过滤器,after_post_render,在每一篇文章生成后,都会调用这个函数,在函数里面,我抽取了文章的content中的img标签的src,并把他放到了变量page.photos里面,这样在index.swig里面就可以使用这个page.photos了,默认是没有这个里面是个空数组
1 | hexo.extend.filter.register('after_post_render', function(data){ |
3.8.分页插件(添加layui分页插件)
首先引入layui组件的js,在index.swig(或者其他被引入的swig文件)
1 | <script type="text/javascript" src="{{ url_for(theme.js) }}/src/page_index.js"></script> |
然后在index.swig模板文件中添加以下代码,主要含义即通过将page分页信息挂载到dom元素的属性上,然后再通过js文件动态生成分页信息。目前没有找到直接在js中获取hexo全局变量的方法。
1 | <div class="pagination_wrap" data-totalpage="{{page.total}}" data-current="{{page.current}}" data-perpage="{{per_page}}"> |
3.9.添加评论
添加评论这个挺简单的,只需要按照参考文章1中的内容进行配置就好了。
我这里还有一个问题,就是有些文章中没有评论,但是会显示一些相关评论的文章,看起来非常的难看,我想着直接把这个给清掉好了。
(1) 第一种方式就是直接使用代码进行控制。
1 | function loadComments () { |
(2) 第二种方法就是,可以通过 Disqus 按右上角的 Admin 進入後台管理,选择要管理的站点,然后找到 Settings,选择Recommendations,这里面有相关的配置。可以关闭显示,甚至可以直接关闭
How do I manually set the images for my Recommendations 这里也显示如何配置图片
1.Disqus评论插件 用这个代码就好了
2.一起来踩配置 Disqus 的坑
3.Hexo NexT 添加 Disqus 评论区
4.获取多说和 Disqus 文章评论数的方法 这里就是显示评论数的一种方法
5.Disqus 有评论但没显示的一种解决方案
6.如何安裝 Disqus 留言板 最簡單的方法就是到後台設定語言,請到 Disqus 按右上角的 Admin 進入後台管理。找到 Settings > General 後,向下拉會找到「Language」項目,選擇好語言後按下方藍色的「Save」保存,留言板的語言就更新成功了!
3.10.遍历显示文章的tags,categories(解决错误Unhandled rejection TypeError: Converting circular structure to JSON)
我打算在文章的首页文章列表的上,显示每篇文章的类别和标签,我尝试使用
1 | {% for categ in post.categories%} |
但是不幸的是出现了“Unhandled rejection TypeError: Converting circular structure to JSON”错误。
于是我在上面(7)的基础上return data之前加入了
1 | console.log(data); |
一步步输出,终于查到了,post.categories的数据格式。
在github上有这么一个解决方案:issues/2189 但是实际上,对于swig模板来说,本身是没有forEach这个函数的。
1 | post.categories.forEach(function(item){ |
终于在一篇博客中发现了蛛丝马迹:hexo-theme-guide ,我就差一个.name了
1 | {% set i = 0 %} |
3.11.根据分类自动生成网站顶部菜单
为了处理自定义的菜单和系统分类菜单,我在第七步的过滤器中添加了如下函数在过滤器template_locals中添加,将在theme配置文件中自定义的菜单type_menu和文章分类合并成了一个headermenu变量,注入到locals中,在文章中即可使用site.headermenu变量,通过遍历这个数组,可以生成一个菜单目录。
1 | var _uniqBy=require("lodash/uniqBy"); |
其实主要思想就是,我把自定义的菜单和hexo生成的文章分类都放到一个menu数组里了,然后根据这个数组生成一个菜单,这个菜单可以说相当复杂,如果菜单数超过4个,就把剩下的放到更多里面,如果没有超过四个,那就挨个排列显示。如果菜单有子菜单,还要把他放到dd标签里面,再更多这一栏的下拉菜单中,还有可能生成三级菜单。首先判断菜单数是否大于4个,不大于3个,就直接遍历生成菜单,如果有子菜单的话,就多套一层。如果菜单数大于4个,先是遍历,把前四个生成出来,然后添加一个更多按钮,再遍历一次菜单数组,将前4个过滤掉,从第四个开始遍历,挨个添加到更多这一个菜单中,如果在遍历的过程中,发现这个菜单有子菜单,那就再遍历一遍子菜单生成一层,如果没有子菜单了,就直接输出菜单明就好了。(费老劲了,都不知道这有啥用。)
1 | <nav class="site-nav"> |
实现的效果如下:
接下来的计划
1.404页面添加
2.seo优化
3.用vscode编写hexo还是有点不方便,修改文章标题,修改文章文件名、复制照片都有点不方便,需要写个应用程序。