Hexo主题开发手记(1)

最近抽空学习了一下前端的基础知识,在之前我也抽空看了相关知识,但是发现没有实践而且不够系统,所以索性这次借着hexo博客搭建来巩固和实践一下所学。

准备

虽然我们是开发hexo的博客主题,但是为了方便我们开发中调试和预览,所以我们还是首先得安装hexo到我们本地目录。

1
hexo init 搭建hexo主题

注意,上面的“搭建hexo主题”是我本地的一个目录。

然后发布,http://localhost:4000 查看

1
2
cd 搭建hexo主题
hexo server

hexo主题

这个是hexo预置的主题landspace,接下来还需要安装hexo-server和hexo-browsersync。另外我们的主题需要pug和stylus的渲染引擎,所以如下一并安装了:

  • hexo-server : hexo的服务运行环境。
  • hexo-browsersync : 页面自动刷新插件。
  • hexo-renderer-jade : pug的编译工具,内包括了pug的渲染引擎。
  • hexo-renderer-stylus : stylus的渲染引擎。
    1
    npm install hexo-server hexo-browsersync hexo-renderer-jade hexo-renderer-stylus --save-dev

注意,新版的hexo-renderer-jade已经包括了处理pug的渲染引擎。

主题结构

通常来说一个hexo主题需要包括下面元素:

  1. 首页 Home
  2. 归档页 Archive
  3. 标签页 Tag
  4. 分类页 Category
  5. 文章页 Post
  6. 页面详情页 Page

这些页面文件都要放到layout目录里。构建的时候将会读取里面的内容进行编译。像CSS,JS,IMG这些都可以算作是资源文件,构建的时候作为引用的资源。这些都放到source目录里。

生成结构

生成Hexo主题的话,用Yeoman是很方便的。如果系统里没有首先先安装一下npm install yo -g,然后再安装一下npm install generator-hexo-theme -g。(注意全局安装可能需要权限)于是我们就拥有了一个可以生成主题目录结构的脚手架工具。

进入之前创建好的Hexo的博客目录,找到themes文件夹,进入。然后yo hexo-theme,这样就会自动生成对应选项,根据选项我们选择pug和stylus,给这个主题命名为temp。然后就会生成一个还不错的项目目录结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── _config.yml # 主题配置文件
├── layout # 布局文件夹
│ ├── archive.pug # 归档页
│ ├── category.pug # 分类页
│ ├── includes # 复用的公共页
│ │ ├── layout.pug # 页面布局
│ │ ├── pagination.pug # 翻页模板
│ │ └── recent-posts.pug # 文章列表模板
│ ├── index.pug # 主页
│ ├── page.pug # 页面详情页
│ ├── post.pug # 文章详情页
│ └── tag.pug # 标签页
└── source # 资源文件夹
├── css # CSS
│ └── temp.styl
├── favicon.ico # 站点图标
└── js # JS
└── temp.js

配置根目录的_config.xml来设置主题为dp2px

1
theme: dp2px

启动hexo服务

1
hexo server

hexo启动服务

查看我们的主题页面如下(为了看起来直观,我拷贝了文章到_post目录):

hexo文章页面

可以看到首页没有任何样式,接下来我们就需要来完善这些页面的布局和样式了。

配置首页链接

我也是初次使用pug,所以看的不是很明白,没关系,我们来先做一下熟悉的事情,配置首页的菜单和链接。

1
2
3
4
5
6
7
# main menu navigation
menu:
首页: /
关于: /about
归档: /archives
标签: /tags
分类: /categories

然后用我们最熟悉的命令创建tags和categories目录

1
2
3
4
>>> $ hexo new page tags
INFO Created: ~/Documents/搭建hexo主题/source/tags/index.md
>>> $ hexo new page categories
>>> INFO Created: ~/Documents/搭建hexo主题/source/categories/index.md

OK!接下来我们分别打开这两个index.md文件并分别添加一个type: tags 和 type: categories

1
2
3
title: categories
date: 2018-10-24 19:24:07
type: categories

来开始编辑我们第一个pug页面,打开themes/dp2px/page.pug,追加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extends includes/layout.pug

block content
if page.type === 'tags'
.tag-cloud
.tag-cloud__title= page.title
| -
span.tag-cloud__amount= site.tags.length
.tag-cloud-tags!= tagcloud({min_font: 12, max_font: 30, amount: 200, color: true, start_color: '#A4D8FA', end_color: '#0790E8'})
else if page.type === 'categories'
.category-lists
.category__title= page.title
| -
span.category__amount= site.categories.length
div!= list_categories()
else
article#page
h1= page.title
!= page.content
div!= paginator()

上面的tagcloud()函数是官方提供的生成标签云的函数,参考链接:https://hexo.io/zh-cn/docs/helpers.html#tagcloud

同样list_categories()函数也是官方提供的生成分类列表的函数,参考链接:https://hexo.io/zh-cn/docs/helpers.html#list-categories

这样我们的tags页面和categories页面就可以显示出来了。

hexo的tags和categories

各个pug文件的关系分析

index.pug

首先我们打开index.pug文件

1
2
3
4
5
extends includes/layout.pug

block content
include includes/recent-posts.pug
div!= paginator()

看到这个index.pug继承了layout.pug。
对layout中的block content进行了覆盖,引入了recent-posts.pug

paginator()函数是官方提供生成分页链接的,可以设置它的样式,参考链接:https://hexo.io/zh-cn/docs/helpers.html#paginator

recent-posts.pug

在index.pug中我们看到content中引入了recent-posts.pug

1
2
3
4
5
6
7
8
if page.posts.length > 0
#recent-posts
h1 Recent Posts
each post in page.posts.sort('date', -1).limit(10).toArray()
.recent-post-item
a(href=config.root + post.path)= post.title
if post.date
time(datetime=post.date.toJSON())= date(post.date, date_format)

我们看到这里主要是遍历了page.posts.在hexo中有很多预置变量,page就是。

变量描述
site网站变量
page针对该页面的内容以及 front-matter 所设定的变量。
config网站配置
theme主题配置。继承自网站配置。
_ (单下划线)函数库
path当前页面路径(不含根路径)
url当前页面完整网址
env环境变量

关于其他变量的详细请查看官方文档:https://hexo.io/zh-cn/docs/variables

上面的page.posts是页面文章对象,我们看到使用limit(10)拿出了前10个文章显示。

所以,recent-posts.pug是首页最近发布的文章列表。

layout.pug

layout.pug是hexo主题页面中最重要的页面,因为几乎所有页面都继承自它。它提供了一个基础的页面结构模板。

最上面定义了一个pageTitle变量,并根据条件赋值

1
2
3
4
5
6
7
- var pageTitle = page.title || config.subtitle || ''
- if (is_archive()) pageTitle = 'Archives'
- if (is_tag()) pageTitle = 'Tag: ' + page.tag
- if (is_category()) pageTitle = 'Category: ' + page.category
- if (is_month()) pageTitle += ': ' + page.month + '/' + page.year
- if (is_year()) pageTitle += ': ' + page.year
- pageTitle += ' [ ' + config.title + ' ]'

其中 is_archive()、is_tag()这几个函数都是预置函数,判断页面类型的。

接下来定义了head头

1
2
3
4
5
6
7
8
head
meta(charset='UTF-8')
title= pageTitle
if theme.stylesheets !== undefined && theme.stylesheets.length > 0
//- stylesheets list from config.yml
each url in theme.stylesheets
link(rel='stylesheet', href=url)
link(rel="icon", href=config.root + 'img/favicon.png')

可以看到样式文件通过themes下面的_config.yml中的theme.stylesheets来配置。

接下来body中定义了页面菜单、内容模板、以及页脚说明、最后通过theme.scripts加载了js文件。

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
body
#menu-outer
nav#menu-inner
each url, label in theme.menu
a(href=url)= label
#content-outer
#content-inner
if body
div!= body
else
block content
#bottom-outer
#bottom-inner
span Site construction by
span= ' ' + config.author + ' '
span using
a(href='http://hexo.io')
span hexo blog framework
span .
br
a(href=config.root) Home
if theme.scripts !== undefined && theme.scripts.length > 0
//- scripts list from config.yml
each url in theme.scripts
script(src=url)

所以,对于我们来说核心的任务是完成这个layout.pug的布局和样式。