如何编写Hexo主题
完成一个Hexo的主题其实很简单,和写静态页面差不多,只是内容部分通过Hexo的变量去获取,而且Hexo还内置了一些辅助函数帮你快速方便地完成繁琐的处理。
起步
在写代码之前要先把项目结构搭建好,一个Hexo主题的项目名就是主题名字本身,项目内的目录结构如下: (生成树形图是用的tree, mac上直接brew install tree就可以了,以前不写都不知道囧)
.
├── _config.yml //记录主题配置信息
├── layout //存放布局模板文件
│ └── _partial //布局文件中可共用的模板
└── source //静态资源文件夹
├── css
├── fonts
├── js
└── sass
项目结构搞好就可以开始写代码了!因为当初我是仿landscape写的,而且ejs也是我之前看nodejs时就接触过的,因此就直接用ejs写模板文件了,样式使用了sass (scss。
布局
编写布局文件(layout.ejs)
模板文件在layout文件夹下,文件名对应Hexo中的模板名,有index,post,page,archive,category,tag几种,对于普通的header + content + footer的页面结构,header和footer往往是可以复用的,因此我们可以使用layout.ejs进行布局,动态的内容使用body变量去动态渲染,所以我的layout.ejs大概长这样:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<title><%= config.title %></title>
<%- css('css/style') %>
</head>
<body>
<%- partial('_partial/header') %>
<div class="main">
<%- body %>
</div>
<%- partial('_partial/footer') %>
<%- js('js/index.js') %>
</body>
</html>
partial,js和css是Hexo提供的辅助函数,后面再说。
其他模板文件
每一个模板文件对应的是一种布局,当你使用hexo new <title>的时候,其实忽略了一个参数,完整的命令是hexo new [layout] <title>,这个layout就决定了文章使用何种方式布局,比如创建一个自己简介的About页面,hexo new page "about"其实就是使用了page布局。每种布局对应到我们的模板文件上就是index.ejs(首页),post.ejs(文章),archive.ejs(归档),tag.ejs(标签归档),page.ejs(分页)。
如果更直观一点,url和模板的对应关系是这样的:
| Url | Description | Layout |
|---|---|---|
| / | 首页 | index.ejs |
| /yyyy/mm/dd/:title/ | 文章 | post.ejs |
| /archives/ | 归档 | archive.ejs |
| /tags/:tagname/ | 某个标签的归档 | tag.ejs |
| /:else/ | 其他 | page.ejs |
index.ejs
首页一般是一些博文的摘要和一个分页器,通过Hexo的page变量拿到页面的数据渲染即可,这里我们不直接在index.ejs中写HTML结构,新建一个_partial/article.ejs,将文章数据传给子模板渲染,然后再额外传入一个参数{index: true},对后面的post.ejs和page.ejs加以区分,让子模板能正确渲染。最后,index.ejs大致是这样的:
//index.ejs
<% page.posts.each(function(post, index){ %>
<%- partial('_partial/article', {index: true, post: post}) %>
<% }) %>
<div class="pagination">
<%- paginator({ total: Math.ceil(site.posts.length / config.per_page)}) %>
</div>
post.ejs
文章模板和首页差不多,只是对应的是一篇具体的文章,所以就把文章传入,再额外传入{index: false}告诉子模板不要按首页的方式去渲染就好了。就一行代码(因为都在子模板里 XD
//post.ejs
<%- partial('_partial/article', {index: false, post: page}) %>
page.ejs
我个人对Page模板其实是有点懵逼的,在我自己的实践中是添加about(hexo new page "about")页面后,访问/about会走分页布局,实际上这个页面对应的内容是/source/about里的index.md,也相当于对文章的渲染,因此我把Page模板也写成了和文章模板一样:
//page.ejs
<%- partial('_partial/article', {index: false, post: page}) %>
_partial/article.ejs
前面一共有三处共用了article模板,另外page和post的一样的,所以实际上只有两种情况:主页(index: true)和非主页(index: false)。对应的_partial/article.ejs里只要判断这个值就可以正确渲染了,基本结构如下:
//_partial/article.ejs
<% if(index){ %>
//index logic...
<% }else{ %>
//post or page logic...
<% } %>
tag.ejs
标签归档页内容很少,直接用Hexo的辅助函数list_tags生成一个标签的列表就ok了:
//tag.ejs
<%- list_tags() %>
归档页模板和首页差不多,归档页只需要展示文章标题和最后的分页器就好:
//archive.ejs
<div class="archive">
<% var lastyear; %>
<% page.posts.each(function(post){ %>
<% var year = post.date.year() %>
<% if(lastyear !== year){ %>
<h4 class="year"><%= year %></h4>
<% lastyear = year %>
<% } %>
<div class="archive_item">
<a class="title" href="<%- url_for(post.path) %>"><%= post.title %></a>
<span class="date"><%= post.date.format('YYYY-MM-DD') %></span>
</div>
<% }) %>
<div class="pagination">
<%- paginator({ total: Math.ceil(site.posts.length / config.per_page)}) %>
</div>
</div>
至此,模板文件就写好了,对于category模板就放弃了,感觉比较鸡肋。。。
变量
其实在模板文件中我们已经看到了page.post,site.posts.length,config.per_page等等,页面的内容就是根据这些变量获取的,由Hexo提供,拿来直接用,Hexo提供了很多变量,但不是都很常用,一般就用到以下变量:
site: 对应整个网站的变量,一般会用到site.posts.length制作分页器page: 对应当前页面的信息,例如我在index.ejs中使用page.posts获取了当前页面的所有文章而不是使用site.posts。config: 博客的配置信息,博客根目录下的_config.yml。theme: 主题的配置信息,对于主题根目录下的_config.yml。
辅助函数(Helper)
制作一个分页器,我们需要知道文章的总数和每页展示的文章数,然后通过循环生成每个link标签,还要根据当前页面判断link标签的active状态,但是在Hexo中这些都不用我们自己来做了!Hexo提供了paginator这一辅助函数帮助我们生成分页器,只需要将文章总数site.posts.length和每页文章数config.per_page传入就可以生成了。
其他的Helper:
list_tags([options]): 快速生成标签列表js(path/to/js),css(path/to/css)用来载入静态资源,path可以是字符串或数组(载入多个资源),默认会去source文件夹下去找。partial(path/to/partial)引用字模板,默认会去layout文件夹下找。
样式
知道了Hexo的渲染方式,我们就可以使用HTML标签+CSS样式个性化我们的主题了,推荐大家使用CSS预处理语言的一种来写样式,这样就可以通过预处理语言自身的特点让样式更灵活。
其他
添加对多说和Disqus的支持
评论是很常用的功能,不如就直接在我们的主题里支持了,然后通过配置变量决定是否开启,评论区跟在文章内容下面,对于这种三方的代码块,最好也以partial的方式提取出来,方便移除或是替换。
//_partial/article.ejs
<section class='post-content'>
<%- post.content %>
</section>
//评论部分,post.comments判断是否开启评论,config.duoshuo_shortname
和config.disqus_shortname来判断启用那种评论插件,这里优先判断了多说
<% if(post.comments){ %>
<section id="comments">
<% if (config.duoshuo_shortname){ %>
<%- partial('_partial/duoshuo') %>
<% }else if(config.disqus_shortname){ %>
<%- partial('_partial/disqus') %>
<% } %>
</section>
<% } %>
再将多说和Disqus提供的js脚本代码放在_partial/duoshuo.ejs和_partial/disqus.ejs下就ok了~
使用highlight.js提供代码高亮
highlight.js提供了多种语言的支持和多种皮肤,用法也很简单,载入文件后调用初始化方法,一切都帮你搞定,对于使用那种皮肤,喜好因人而异,我们干脆在主题的配置文件中做成配置项让用户自己选择:
//showonne/_config.yml
...other configs
# highlight.js
highlight_theme: zenburn
对应的layout.ejs中:
样式文件通过CDN引入,因为不同皮肤对应不同的文件名,所以十分灵活。
最后
当初是对应着landscape照葫芦画瓢写的,最近回头来发现一些不合理的地方,所以就又改了改,也对应着写了这么一篇总结,接下来准备再把样式划分一下,对于颜色这类样式通过变量的方式提取出来,也变得可配置,能让主题更灵活一些。
参考资源
了解辅助函数
模板
Hexo中的变量
Hexo主题列表
Hexo使用多说教程
How to use highlight.js
如何编写Hexo主题的更多相关文章
- Github Pages 搭建HEXO主题个人博客
跌跌撞撞,总算是建立起来了.回首走过的这么多坑,也真的是蛮不容易的.那么就写点东西,记录我是怎么搭建的吧. 准备工作 安装Node.js: 用于生成静态页面,我们需要到官网上去下载即可.http:// ...
- 从零开始制作 Hexo 主题
原文地址:从零开始制作 Hexo 主题 · Ahonn 写在前面 本文将会从零开始开发一个简单的博客主题.样式主要参考 Hexo theme 中的 Noise 主题. 开始之前你需要了解: 模板引擎 ...
- Hexo主题开发
序章 想要一个自己的知识管理系统,用了 Hexo ,但是没有发现自己心仪的主题,就自己做了一个.本文记录了制作的全过程.本人编码功底和前端知识并不是特别雄厚,希望能由此文引出各路大神的兴趣,以后制作出 ...
- 使用vim编写hexo文档,并用ultisnips/snipmates/snippets插件补全
作为一个vim使用者,编写markdown文档时若不能用vim这怎么能受的了! 下面是我编写markdown的时候用到的插件 Plugin 'Markdown'Plugin 'Markdown-syn ...
- 从0开始的Hexo主题制作
从0开始的Hexo主题制作 从零开始制作 Hexo 主题 H2O主题 先坑着
- 推荐5款简洁美观的Hexo主题
2018-11-17 17:15:46 原文地址:http://www.izhongxia.com 以下是 <hexo 主题列表> 中挑选出来一些比较简洁美观的主题(存在个人主观意识,请勿 ...
- hexo主题中添加相册功能
博客已迁移至http://lwzhang.github.io. 基本上所有的hexo主题默认都没有实现相册功能,一方面相册功能的需求较少,毕竟hexo主要是写博客用的:另一方面实现相册功能比较麻烦,比 ...
- hexo干货系列:(二)hexo主题下载及配置
前言 上一篇文章介绍了hexo+gitHub简易搭建属于自己的个人独立博客,但是主题是默认的landscape,略显简单,今天的教程推荐Jacman主题. Jacman是一款为Hexo打造的一款扁平化 ...
- 推荐一款好看的Hexo主题Ayer
介绍 Ayer 是一个干净且优雅的Hexo主题,自带响应式,加载速度很快,该有的功能都有,可配置项也很多,非常适合作为你的博客主题,主题内还附送了6张精美的高清壁纸.欢迎使用和Star支持,如果你在使 ...
随机推荐
- JS里引用CSS属性时候的命名
如果JS代码中设置<p>元素的另一个CSS属性font-family.这个属性的获取方式与color属性略有不同,因为 font和family之间的连字符与JS中减法操作符相同,J ...
- HTML解析器BeautifulSoup
BeautifulSoup是Python的一个库,可解析用urllib2抓取下来的HTML 1.Beautiful Soup 安装 可以利用 pip 来安装,在Python程序中导入 pip inst ...
- MySQL Online DDL的改进与应用
本文简析Online DDL的实现原理与使用过程注意事项. 任何DDL操作,执行者都需要预先测试或者清晰了解这个操作会给数据库带来的影响是否是在业务期间数据库的可承受范围内,尤其是 ...
- PHP的laravel框架后台实现数据导出excel的功能
要想在PHP后台实现excel导入导出功能,一种简单有效的方法就是使用phpexcel插件. 要使用phpexcel插件,首先需要下载composer,这个工具是专门用来管理项目中库之间的依赖关系的. ...
- 【小瑕疵】在div里插入img后在底部留有缝隙怎么解决
[本文转载自http://blog.sina.com.cn/s/blog_9fd5b6df01013mld.html] 图片IMG与容器下边界之间有空隙怎么办?这里介绍3中简单的解决方法. 第一,给图 ...
- cmd中添加snmpd被控
在cmd中添加snmpd被控,减少手动操作步骤. net stop sharedaccess reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\s ...
- Intellij IDEA注册server
版权声明:本文为博主原创文章,未经博主允许不得转载.转载请注明来源:http://blog.csdn.net/mingjie1212.欢迎交流学习!对于Intellij IDEA 2016.3.4 ...
- ThinkPHP 框架模型
1 在MainController.class.php 控制器中有一个test的方法,同时还有一个deng的方法,我想在test方法中使用deng方法 表示为 <?php namespace ...
- stl_各容器的总结
一.stl容器总结: 1.以下的操作是在一千万的数据下操作.copy 都是在足够的空间下进行的copy, 测量方式: std::clock_t start = std::clock(); //待测代码 ...
- 分针网—IT教育:作为PHP开发人员容易忽视的几个重点
无论是学习什么样的一个开发.ASP开发.java开发.当学习还不是很久的时候,一般都是不知道它们的精华是在哪里,而现在很多的php程序员也是不知道PHP的精华所在,为什么perl在当年在商界如此的出名 ...