如何編寫Hexo主題

完成一個Hexo的主題其實很簡單,和寫靜態頁面差很少,只是內容部分經過Hexo的變量去獲取,並且Hexo還內置了一些輔助函數幫你快速方便地完成繁瑣的處理。css

起步

在寫代碼以前要先把項目結構搭建好,一個Hexo主題的項目名就是主題名字自己,項目內的目錄結構以下: (生成樹形圖是用的tree, mac上直接brew install tree就能夠了,之前不寫都不知道囧)html

.
├── _config.yml   //記錄主題配置信息
├── layout        //存放佈局模板文件
│   └── _partial  //佈局文件中可共用的模板
└── source        //靜態資源文件夾
    ├── css
    ├── fonts
    ├── js
    └── sass

項目結構搞好就能夠開始寫代碼了!由於當初我是仿landscape寫的,並且ejs也是我以前看nodejs時就接觸過的,所以就直接用ejs寫模板文件了,樣式使用了sass (scssnode

佈局

編寫佈局文件(layout.ejs)

模板文件在layout文件夾下,文件名對應Hexo中的模板名,有index,post,page,archive,category,tag幾種,對於普通的header + content + footer的頁面結構,headerfooter每每是能夠複用的,所以咱們可使用layout.ejs進行佈局,動態的內容使用body變量去動態渲染,因此個人layout.ejs大概長這樣:api

<!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,jscss是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(分頁)sass

若是更直觀一點,url和模板的對應關係是這樣的:hexo

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.ejspage.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模板也寫成了和文章模板同樣:post

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

相關文章
相關標籤/搜索