Hexo主题开发手记(1)

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

准备

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

hexo init 搭建hexo主题

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

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

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的渲染引擎。

    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。然后就会生成一个还不错的项目目录结构。

.
├── _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

theme: dp2px

启动hexo服务

hexo server

hexo启动服务

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

hexo文章页面

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

配置首页链接

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

# main menu navigation
menu:
  首页: /
  关于: /about
  归档: /archives
  标签: /tags
  分类: /categories

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

>>> $ 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

title: categories
date: 2018-10-24 19:24:07
type: categories

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

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文件

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

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变量,并根据条件赋值

- 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头

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文件。

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的布局和样式。