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还是有点不方便,修改文章标题,修改文章文件名、复制照片都有点不方便,需要写个应用程序。
