從零開始製做 Hexo 主題

原文地址: 從零開始製做 Hexo 主題 · Ahonn css

寫在前面

本文將會從零開始開發一個簡單的博客主題。樣式主要參考 Hexo theme 中的 Noise 主題。 html

開始以前你須要瞭解:git

  • 模板引擎github

  • CSS預處理器sass

  • Hexo 文檔服務器

本文使用的模板引擎爲 ejs,使用的 CSS 預處理器爲 stylus。這也是 hexo 項目預裝了的 render 插件,若是想使用其餘模板引擎或者其餘 CSS 預處理器,能夠安裝相對應的 render 插件。例如個人 Even 主題使用的是 Swig 與 SCSS。hexo

本文的代碼: theme-exampleless

目錄結構

主題目錄結構以自帶的 landscape 主題爲例:函數

.
├── languages  語言文件,用於國際化
├── layout     頁面模板文件
├── scripts    Hexo 腳本
└── source     主題資源文件,包括頁面樣式,腳本,字體等

咱們在 themes 中新建 theme-example 文件夾,而後在 theme-demo 中按照 landscape 主題的目錄結構新建 languageslayoutscriptssource 文件夾。佈局

建立佈局模板

layout 中建立 index.ejs 文件,首頁將會使用該佈局模板生成 HTML 文件。

layout/index.ejs:

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
    <title>Home</title>
  </head>
  <body>
    <h1>Hello Word</h1>
  </body>
</html>

修改站點配置文件中的主題配置,使用咱們剛剛建立的 theme-example 主題:

# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: theme-example

運行 hexo server --debug 以 debug 模式開啓 Hexo 本地服務器預覽,訪問 http://localhost:4000/

Hello World

添加頁面導航

如今咱們須要在頁面中添加導航,因爲導航不僅僅會在首頁出現,因此咱們在 layout 中建立共用的佈局文件 layout.ejs, 同時建立 _partial/head.ejs 保存 HTML 的 head 以及建立 _partial/header.ejs 文件,編寫頁面導航部分。

layout/layout.ejs:

<!DOCTYPE html>
<html>
  <%- partial('_partial/head') %>
  <body>
    <%- partial('_partial/header') %>
    <main class="main">
      <%- body %>
    </main>
  </body>
</html>

layout.ejs 文件經過 partial() 函數來包含其餘文件,使得咱們可以更好的組織代碼。詳見 Templates | Hexo

layout/_partial/head.ejs:

<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <title><%= config.title %></title>
</head>

這裏使用了 config 變量,該變量包含的是站點配置(即站點根目錄下 _config.yml 中的配置)。除此以外,Hexo 還提供了許多變量可在模板中使用,詳見 Variables | Hexo

layout/_partial/header.ejs:

<header class="header">
  <div class="blog-title">
    <a href="<%- url_for() %>" class="logo"><%= config.title %></a>
  </div>
  <nav class="navbar">
    <ul class="menu">
      <li class="menu-item">
        <a href="/" class="menu-item-link">Home</a>
      </li>
      <li class="menu-item">
        <a href="/archives" class="menu-item-link">Archive</a>
      </li>
    </ul>
  </nav>
</header>

接着咱們清空 index.ejs 中的內容,並添加 <h2>Hello World</h2>。在 layout 目錄下的 index.ejs 會自動繼承 layout.ejs,並將其中的內容填入 <%- body %> 的位置。咱們將獲得一個有導航菜單的 Hello World 頁面。

添加主題配置文件

實際上咱們須要讓導航菜單根據咱們的須要顯示不一樣的項,上面這種寫法不方便修改。因此咱們會在主題的配置文件中添加導航菜單的配置。在 thmem-demo 下新建主題的配置文件 _config.yml,在其中添加須要配置的字段。而後能夠經過 theme 這個變量來拿到該配置文件中的配置。

theme-demo/_config.yml:

menu:
  Home: /
  Archives: /archives

這樣咱們就能夠在 header.ejs 中使用 theme.menu 獲取到導航菜單的設置。將 header.ejs 修改成:

<header class="header">
  <div class="blog-title">
    <a href="<%- url_for() %>" class="logo"><%= config.title %></a>
  </div>
  <nav class="navbar">
    <ul class="menu">
      <% for (name in theme.menu) { %>
        <li class="menu-item">
          <a href="<%- url_for(theme.menu[name]) %>" class="menu-item-link"><%= name %></a>
        </li>
      <% } %>
    </ul>
  </nav>
</header>

當須要在導航中添加連接的時候就能夠在配置文件中直接添加,例如添加 Github 的連接:

menu:
  Home: /
  Archives: /archives
  Github: https://github.com/ahonn

除此以外還能夠添加其餘須要的配置,例如 RSS,評論等等。

添加首頁文章列表

接着咱們完善首頁的模板,使其可以顯示文章列表。前面已經說過 Hexo 提供了各類有用的變量,在這裏將會使用到 page 這個變量。page 會根據不一樣的頁面擁有不一樣的屬性。具體有什麼屬性,能夠獲取到哪些數據能夠查看這裏

那麼這裏咱們會使用 page 變量的 posts 屬性拿到文章數據的集合。編輯 index.ejs 文件:

<section class="posts">
  <% page.posts.each(function (post) { %>
    <article class="post">
      <div class="post-title">
        <a class="post-title-link" href="<%- url_for(post.path) %>"><%= post.title %></a>
      </div>
      <div class="post-content">
        <%- post.content %>
      </div>
      <div class="post-meta">
        <span class="post-time"><%- date(post.date, "YYYY-MM-DD") %></span>
      </div>
    </article>
  <% }) %>
</section>

page.posts 中獲取單篇文章的數據,並獲取文章的標題,內容等數據填充到模板中。處理文章建立時間的時候使用了 date() 函數,這是 Hexo 提供的時間處理的輔助函數。本文中使用到的函數如無特別說明,即爲 Hexo 的輔助函數。

文章摘錄

因爲首頁顯示文章內容時使用的是 post.content,即文章的所有內容。因此首頁會顯示每一篇文章的內容,實際上咱們並不想在首頁顯示那麼多內容,只想顯示文章的摘錄。

Hexo 提供了 excerpt 屬性來獲取文章的摘錄部分,不過這裏須要在文章中添加一個 <!-- more --> 標記。添加了這個標記以後,post.excerpt 將會獲取到標記以前的內容。若是沒有這個標記,那麼 post.excerpt 會是空的。因此咱們能夠把首頁文章內容部分的 post.content 替換成 post.excerpt

<div class="post-content">
  <%- post.excerpt %>
</div>

添加頁面樣式

到目前爲止,咱們完成了首頁的頁面結構,可是並無添加樣式,因此看起來很醜。咱們在 source 文件中建立一個 css 文件夾來存放樣式文件。

因爲 Hexo 在新建項目的時候會安裝 hexo-renderer-stylus 這個插件,因此咱們無需其餘步驟,只須要將樣式文件放到 css 文件夾中。Hexo 在生成頁面的時候會將 source 中的全部文件複製到生成的 public 文件中,而且在此以前會編譯 styl 爲 css 文件。

css 文件夾中建立 style.styl,編寫一些基礎的樣式,並把全部樣式 import 到這個文件。因此最終編譯以後只會有 style.css 一個文件。建立 _partial/header.styl_partial/post.style 存放頁面導航以及文章的樣式,而且在 style.stylimport 這兩個文件。

_partial/header.styl:

.header {
  margin-top: 2em
  display: flex
  align-items: baseline
  justify-content: space-between

  .blog-title .logo {
    color: #AAA;
    font-size: 2em;
    font-family: "Comic Sans MS",cursive,LiSu,sans-serif;
    text-decoration: none;
  }

  .menu {
    margin: 0;
    padding: 0;

    .menu-item {
      display: inline-block;
      margin-right: 10px;
    }

    .menu-item-link {
      color: #AAA;
      text-decoration: none;

      &:hover {
        color: #368CCB;
      }
    }
  }
}

_partial/post.style:

.post {
  margin: 1em auto;
  padding: 30px 50px;
  background-color: #fff;
  border: 1px solid #ddd;
  box-shadow: 0 0 2px #ddd;
}

.posts  {
  .post:first-child {
    margin-top: 0;
  }

  .post-title {
    font-size: 1.5em;

    .post-title-link {
      color: #368CCB;
      text-decoration: none;
    }
  }

  .post-content {
    a {
      color: #368CCB;
      text-decoration: none;
    }
  }

  .post-meta {
    color: #BABABA;
  }
}

style.styl:

body {
  background-color: #F2F2F2;
  font-size: 1.25rem;
  line-height: 1.5;
}

.container {
  max-width: 960px;
  margin: 0 auto;
}

@import "_partial/header";
@import "_partial/post";

最後,咱們須要把樣式添加到頁面中,這裏使用了另一個輔助函數 css():

layout/_partial/head.ejs

<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <title><%= config.title %></title>
  <%- css('css/style.css') %>
</head>

至此,咱們會看到站點的首頁是這個樣子的:

添加分頁

在站點的 source/_post/ 目錄下存放的是咱們的文章,如今咱們把本來的 hello-world.md 複製黏貼 10+ 次,再查看站點首頁。會發現,首頁只顯示了 10 篇文章。

首頁顯示的文章數量咱們能夠經過站點配置文件中的 per_page 字段來修改,可是咱們不可能把全部文章都放在一頁,因此咱們如今來添加文章列表的分頁。

新建 _partial/paginator.ejs:

<% if (page.total > 1){ %>
  <nav class="page-nav">
    <%- paginator({
      prev_text: "&laquo; Prev",
      next_text: "Next &raquo;"
    }) %>
  </nav>
<% } %>

index.ejs 中添加這個文件的內容:

...
</section>
<%- partial('_partial/paginator') %>

這裏咱們使用到了另外的一個輔助函數 paginator,它可以幫助咱們插入分頁連接。

添加文章詳情頁

文章詳情頁對應的佈局文件是 post.ejs,新建 post.ejs:

<article class="post">
  <div class="post-title">
    <h2 class="title"><%= page.title %></h2>
  </div>
   <div class="post-meta">
    <span class="post-time"><%- date(page.date, "YYYY-MM-DD") %></span>
  </div>
  <div class="post-content">
    <%- page.content %>
  </div>
</article>

因爲這裏是文章的模板,因此變量 page 表示的是文章的數據,而不是首頁的文章數據集合。

添加歸檔頁

建立歸檔頁使用的模板文件 archive.ejs:

<section class="archive">
  <ul class="post-archive">
    <% page.posts.each(function (post) { %>
      <li class="post-item">
        <span class="post-date"><%= date(post.date, "YYYY-MM-DD") %></span>
        <a class="post-title" href="<%- url_for(post.path) %>"><%= post.title %></a>
      </li>
    <% }) %>
  </ul>
</section>
<%- partial('_partial/paginator') %>

其實結構跟首頁差很少,只是不顯示文章內容而已。添加歸檔頁的樣式:

css/_partial/archive.styl:

.archive {
  margin: 1em auto;
  padding: 30px 50px;
  background-color: #fff;
  border: 1px solid #ddd;
  box-shadow: 0 0 2px #ddd;

  .post-archive {
    list-style: none;
    padding: 0;

    .post-item {
      margin: 5px 0;

      .post-date {
        display: inline-block;
        margin-right: 10px;
        color: #BABABA;
      }

      .post-title {
        color: #368CCB;
        text-decoration: none;
      }
    }
  }
}

國際化

還記得咱們一開始建立的 languages 文件夾嗎?沒錯,它是用來添加多種語言,用於 i18n 的。站點的語言設置爲站點配置文件中的 language

當該字段爲空時,默認使用的是 languages/default.yml 這個文件。那麼如今咱們來添加這個文件,咱們決定主題的默認語言是英文:

Menu:
  Home: Home
  Archives: Archives
  Github: Github

Paginator:
  Prev: Prev
  Next: Next

目前咱們須要主題根據選擇的語言自動修改的有上面這些,接着咱們須要修改 header.ejspaginator.ejs 這兩個文件:

_partial/header.ejs

<header class="header">
  <div class="blog-title">
    <a href="<%- url_for() %>" class="logo"><%= config.title %></a>
  </div>
  <nav class="navbar">
    <ul class="menu">
      <% for (name in theme.menu) { %>
        <li class="menu-item">
          <a href="<%- url_for(theme.menu[name]) %>" class="menu-item-link"><%- __('Menu.' + name) %></a>
        </li>
      <% } %>
    </ul>
  </nav>
</header>

_partial/paginator.ejs:

<% if (page.total > 1){ %>
  <nav class="page-nav">
    <%- paginator({
      prev_text: "&laquo;" + __('Paginator.Prev'),
      next_text: __('Paginator.Next') + "&raquo;"
    }) %>
  </nav>
<% } %>

修改以後其實與以前相比沒有什麼變化,起碼看起來是。如今咱們添加一箇中文的文件:

languages/zh-CN.yml

Menu:
  Home: 首頁
  Archives: 歸檔
  Github: 交友

Paginator:
  Prev: 上一頁
  Next: 下一頁

而後咱們將站點配置文件中的 language 字段修改成 zh-CN(與 zh-CN.yml 文件名相同)。再次訪問站點以後就會發現導航與分頁部分的文字變成了中文。

最後總結

若是你有耐心看我廢話了這麼多的話,恭喜你,你應該對怎麼去寫一個 Hexo 主題有了必定的瞭解。其實說白了,Hexo 就是把那些 Markdown 文件按照不一樣的佈局模板,填上對應的數據生成 HTML 頁面,複製 source 中的到生成的 public 文件夾中,中間過程會把須要編譯的 stylus/less/sass 等文件編譯。

本文並無說起有關頁面 JavaScript 的部分,實際上與寫 CSS 樣式相同。在 source/js 中寫 JavaScript 腳本,而後在模板中引入便可。

感謝閱讀,但願對你有所幫助。

相關文章
相關標籤/搜索