前言:本系列文章翻译自@Jonathan Klughertz的博客,将会用三篇文章的篇幅详细讲解如何制作一个Hexo主题。我不是学翻译出身,若有翻译错误或是不到位之处,请指正。在这个系列教程中,你将学习怎么从零开始制作一个Hexo主题。我很喜欢Hexo,并且每天都在使用,不幸的是,直到今天关于主题制作的文档还是相当稀缺。所以我打算弥补这个空缺。预先准备Hexo博客的基础使用。如果你是第一次接触,请前往官网阅读教程了解Bootstrap了解Javascript模板引擎(我们将使用EJS)项目描述这个项目旨在制作一个Hexo主题并详细了解Hexo引擎的工作方式。我不想在HTML和CSS上花费太多时间,所以我们将重置下面这个Hexo主题:https://getbootstrap.com/docs… 。它是Bootstrap文档中的一个标准初始模板样例。我们将一步步地重用CSS、复制粘贴HTML,直到最后实现想要的效果。如果你感到困惑或者只对它的代码感兴趣,请前往github。项目结构创建一个新的hexo博客让我们从搭建一个全新的hexo博客开始吧# Create a new foldermkdir hexo-theme-creation cd hexo-theme-creation# Initialise Hexohexo init创建主题文件夹# Enter the theme foldercd themes# bootstrap-blog-hexo is also going to be the name of our thememkdir bootstrap-blog-hexo注意:如果你想在git中保存主题的话(你也应该这么做),请在/themes/bootstrap-blog-hexo/中初始化git。文件夹结构这是我们开始工作所需要的文件和文件夹:|– layout // .ejs templates |– source // source files (CSS, scripts)|– _config.yml创建以下两个文件夹和_config.yml文件。/layout/ 将包含我们所有的EJS模板/source/ 将包含我们所有的资源(CSS文件、外部脚本和库)_config.yml 包含我们的主题配置。现在暂且不写入任何内容。复制bootstrap blog源码从bootstrap blog template复制所有我们需要的源码并放在source文件夹里。你可以选择通过浏览器查看源码并复制下来,或者是下载该压缩包,之后解压到source文件夹里。|– layout |– source |– bootstrap // Copy the boostrap library files here |– css // Copy the blog’s css file here |– favicon |– favicon.ico // Your choice of favicon |– js // Copy the blog’s js file here|– _config.ymlHexo的基本要素在我们开始写第一个模板文件之前,先来看看Hexo博客生成过程的基本要素。页面类型我们能够在主题中定义6种页面类型,与之相对应地,在public文件夹生成的每一个单独的HTML页面都属于下面模板中的其中一个:模板备用模板页面描述index无这是博客的首页,也是网站的主要入口。本教程中我们将让其显示文章摘要列表postindex这是文章的详情页。我们将展示一篇完整的文章以及一个评论区pageindex这是页面的详情页,与post一样,但是是page类型的postarchiveindex这是归档页。它将显示我们博客中所有文章的标题和详情页链接categoryarchive这是分类页。与归档页类似,但是会根据类别进行筛选tagarchive这是标签页。与分类页类似,但是会根据标签进行筛选在本篇教程中我们将创建index模板。在页面生成过程中,Hexo将会搜索名字为index.ejs,post.ejs,page.ejs等的文件,这些模板之后用于创建静态HTML页面。公共布局Hexo支持使用公共的布局文件,上面的模板都将使用到该文件。该文件命名为layout.ejs。不同页面类型的模板会创建一些内容,而这个文件就好比这些内容的“外壳”。在我们的主题中,公共布局将包括:<html>标签、<head>标签、头部、菜单、底部和侧边栏。基本上是所有类型的页面都具备的元素。不同的页面模板将只负责创建实际内容,这些内容将放在我们的主体部位。变量在所有的模板中,我们都可以使用hexo引擎提供的内置变量。以下是部分变量:Site:site包含了网站的信息。例如,我们可以通过site.posts访问博客中的所有文章。当我们想要显示统计数据的时候,这将派上用场。Page:page是主要变量,包含了许多与当前页面相关的信息,包括所有的文章标题、日期、内容等。Config:config是一个指向站点_config.yml文件的JavaScript对象Theme:theme是一个指向主题_config.yml文件的JavaScript对象主题的布局创建上面提及了/layout/layout.ejs文件,现在我们开始来创建它。顶部标签首先创建layout.ejs文件并插入<html></html>标签//layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %></html>这里我们将所有<head>标签里的代码提取出来并放在局部视图中,这有助于实现关注点分离和代码重用。语法是partial(‘path’ [, arguments])在创建layout/_partial/head.ejs文件后,从bootstrap源码中复制head标签里的代码:// layout/_partial/head.ejs<head> <meta charset=“utf-8”> <meta http-equiv=“X-UA-Compatible” content=“IE=edge”> <meta name=“viewport” content=“width=device-width, initial-scale=1”> <meta name=“description” content=""> <meta name=“author” content=""> <link rel=“icon” href=“favicon/favicon.ico”> <title>Blog Template for Bootstrap</title> <!– Bootstrap core CSS –> < css(‘bootstrap/css/bootstrap.min.css’) %> <!– IE10 viewport hack for Surface/desktop Windows 8 bug –> < css(‘css/ie10-viewport-bug-workaround.css’) %> <!– Custom styles for this template –> < css(‘css/blog.css’) %> <!– HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries –> <!–[if lt IE 9]> <script src=“https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src=“https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]–></head>这很简单,我们只需使用CSS helper插入样式表。source文件夹中的文件将会被复制到站点根目录下,所以不要在路径中包含source/我们将让<title>和<meta>标签保持动态,不过现在先暂且不管它们。底部标签底部标签位于</body>之前。我们将在这个局部视图中包含所有脚本。先修改一下布局:// layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %><body> <!– After footer scripts –> < partial(’_partial/after-footer’) %></body></html>然后创建layout/_partial/after-footer.ejs的内容:// layout/_partial/after-footer.ejs<script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>< js(‘bootstrap/js/bootstrap.min.js’) %><!– IE10 viewport hack for Surface/desktop Windows 8 bug –>< js(‘js/ie10-viewport-bug-workaround.js’) %>注意JS helper function的使用,它将引用本地js文件。顶部菜单类似地,在<body>标签后创建顶部菜单。// layout/layout.ejs// […]<body> <!– Menu –> < partial(’_partial/menu’) %> // […]layout/_partial/menu.ejs 的内容:// layout/_partial/menu.ejs<div class=“blog-masthead”> <div class=“container”> <nav class=“blog-nav”> <% for (var i in theme.menu){ %> <a class=“blog-nav-item” href="< url_for(theme.menu[i]) %>"><%= i %></a> <% } %> </nav> </div></div>注意theme全局变量的使用,它指向的是主题的_config.yml文件。为了可以在主题配置中配置菜单,我们需要在_config.yml文件中添加配置:_config.yml# Headermenu: Home: / Archives: /archives在menu.ejs中我们遍历了配置文件中所有的菜单项目并创建对应的链接。顶部顶部将位于顶部菜单下面,它包含了博客标题和子标题:// layout/_partial/header.ejs<div class=“blog-header”> <h1 class=“blog-title”><%= config.title %></h1> <p class=“lead blog-description”><% if (config.subtitle){ %><%= config.subtitle %><% } %></p></div>这里我们使用了指向站点_config.yml文件的config变量,它包含了可供配置的标题和子标题属性。注意在布局的<div class=“container”><div>中嵌套顶部:// layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %><body> <!– Menu –> < partial(’_partial/menu’) %> <div class=“container”> <!– Blog Header: title and subtitle –> < partial(’_partial/header’) %> </div> // […]底部底部现在是完全静态的,内容如下:// layout/_partial/footer.ejs<footer class=“blog-footer”> <p>Blog template built for <a href=“http://getbootstrap.com”>Bootstrap</a> by <a href=“https://twitter.com/mdo">@mdo</a>.</p> <p>Adapted to Hexo by <a href=“http://www.codeblocq.com/">klugjo</a>.</p> <p><a href=”#">Back to top</a></p></footer>主要内容和侧边栏此时,我们再加上主要内容和侧边栏,基本就差不多了。下面是最终的layout.ejs:// layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %><body> <!– Menu –> < partial(’_partial/menu’) %> <div class=“container”> <!– Blog Header: title and subtitle –> < partial(’_partial/header’) %> <div class=“row”> <!– Main Content –> <div class=“col-sm-8 blog-main”> < body %> </div> <!– Sidebar –> <div class=“col-sm-3 col-sm-offset-1 blog-sidebar”> < partial(’_partial/sidebar’) %> </div> </div> </div> <!– Footer –> < partial(’_partial/footer’) %> <!– After footer scripts –> < partial(’_partial/after-footer’) %></body></html>body变量对应了不同页面类型模板创建的内容(参见上面)。至于侧边栏,我们现在暂且使用来自bootstrap模板的硬编码:// layout/_partial/sidebar.ejs<div class=“sidebar-module sidebar-module-inset”> <h4>About</h4> <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p></div><div class=“sidebar-module”> <h4>Archives</h4> <ol class=“list-unstyled”> <li><a href=”#">March 2014</a></li> <li><a href=”#">February 2014</a></li> <li><a href=”#">January 2014</a></li> <li><a href=”#">December 2013</a></li> <li><a href="#">November 2013</a></li> </ol></div><div class=“sidebar-module”> <h4>Elsewhere</h4> <ol class=“list-unstyled”> <li><a href="#">GitHub</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Facebook</a></li> </ol></div>首页文件布局到位后,我们就可以开始创建第一个页面类型模板inde.ejs了。这是比较简陋的第一个版本:// layout/index.ejs<span>Content</span>别小瞧它,我们可以用这个在浏览器中测试主题:# Verify that everything is alrighthexo generate# Start hexo serverhexo server访问 http://localhost:4000/ 。哇!注意:不要忘记在站点的config文件中更新主题:_config.yml# Extensions## Plugins: http://hexo.io/plugins/## Themes: http://hexo.io/themes/theme: bootstrap-blog-hexo遍历博客文章我们想要在首页显示各篇文章的摘要。首先,在我们的index.ejs文件中遍历文章:// layout.index.ejs<% page.posts.each(function(item){ %> < partial(’_partial/article-excerpt’, {item: item}) %><% }); %>通过page.posts获取该页面的所有文章通过< partial(’name’, args) %>给partial传参文章布局创建article-excerpt.ejs文件,添加适合主题的代码。这是我的布局:// layout/_partial/article-excerpt.ejs<div class=“blog-post”> <!– Title –> <h2 class=“blog-post-title”> <a href="< config.root %>< item.path %>"> < item.title %> </a> </h2> <!– Date and Author –> <p class=“blog-post-meta”> <%= item.date.format(config.date_format) %> <% if(item.author) { %> by < item.author %> <% } %> </p> <!– Content –> < item.excerpt || item.content %> <!– Only display the Read More link if we are displaying an excerpt –> <% if(item.excerpt) { %> <p> <a href="< config.root %>< item.path %>"> <%= theme.excerpt_link %> </a> </p> <% } %></div>全文链接全文链接是由config.root(配置选项,相当于/)和item.path(相对路径或者绝对路径,指向全文)连接组成的。文章作者默认情况下,Hexo没有关于作者属性的的文章变量。不过我们可以在front matter中添加任意自己想要的变量。如果你想要在文章中显示作者名字,那么文章的front matter应该类似如下进行设置:title: Hello Worldauthor: Klughertz Jonathan—Item excerpt 和 Item content当用Hexo编辑文章时,你可以用<!– more –>标签从文章内容中截取摘要。在本教程中,因为我们展示的是文章列表,所以选择显示摘要。之后用户可以通过点击文章标题或者“阅读更多”的链接浏览全文。“阅读更多”文本别忘了,你需要像我这样在主题的配置文件中添加一个新的属性:_config.yml# Read More textexcerpt_link: Read More希望接下来的代码容易理解。现在,我建议你写一些除了默认的Hello World之外的文章并享受这个结果。分页器在本篇文章中,我们最后需要处理的是首页的分页器。在index.ejs文件中增加一个分页器的partial:// layout/index.ejs<% page.posts.each(function(item){ %> < partial(’_partial/article-excerpt’, {item: item}) %><% }); %>< partial(’_partial/pagination’) %>之后开始创建分页器的内容,layout/_partial/pagination.ejs:// layout/_partial/pagination.ejs<nav> <ul class=“pager”> <% if (page.prev){ %> <li><a href="< config.root %>< page.prev_link %>">Previous</a></li> <% } %> <% if (page.next){ %> <li><a href="< config.root %>< page.next_link %>">Next</a></li> <% } %> </ul></nav>page.prev:上一页的页码。如果当前页是第一页,则为0page.next:下一页的页码。如果当前页是最后一页,则为0page.next_link和page.prev_link是什么就不用多说了。如果你没有足够的文章用来查看分页器的工作效果,可以在主配置文件中(per_page属性)调整每一页的文章数。这就是今天的内容,在下一篇教程中,我们将完成博客剩下的所有页面。