搭建Hexo博客进阶篇---主题自定义(三)

本文续接 Hexo 文档讲解篇

Yelee主题介绍

更换主题

创建 Hexo 主题非常容易,您只要在 themes 文件夹内,新增一个任意名称的文件夹,并修改 _config.yml 内的 theme 设定,即可切换主题。一个主题可能会有以下的结构:

.
├── _config.yml      //这个是主题配置项文件
├── languages        //这个是语言文件
├── layout           //这个是模板文件
├── scripts           
└── source          

盛年不重来,一日难再晨。及时当勉励,岁月不待人

  1. Layout

     布局文件夹。用于存放主题的模板文件,决定了网站内容的呈现方式,Hexo 内建 Swig 模板引擎,您可以另外安装插件来获得 `EJS`、`Haml` 或 `Jade` 支持,Hexo 根据模板文件的扩展名来决定所使用的模板引擎,例如:
    layout.ejs   - 使用 EJS
    layout.swig  - 使用 Swig

    yelle主题采用的是EJS模板,EJS模板可以参考 ejs中文文档

  2. source

    资源文件夹,除了模板以外的 Asset,例如 CSS、JavaScript 文件等,都应该放在这个文件夹中。文件或文件夹开头名称为 _(下划线线)或隐藏的文件会被忽略。

    如果文件可以被渲染的话,会经过解析然后储存到 public 文件夹,否则会直接拷贝到 public 文件夹。

模板

模板决定了网站内容的呈现方式,每个主题至少都应包含一个 index 模板,以下是各页面相对应的模板名称:

模板 用途 回调
index 首页
post 文章 index
page 分页 index
archive 归档 index
category 分类归档 archive
tag 标签归档 archive

布局

如果页面结构类似,例如两个模板都有页首(Header)和页脚(Footer),您可考虑通过「布局」让两个模板共享相同的结构。一个布局文件必须要能显示 body 变量的内容,如此一来模板的内容才会被显示,举例来说:

{% codeblock index,ejs %}
index
{% endcodeblock %}

{% codeblock layout.ejs %}


<%- body %>

{% endcodeblock %}

生成 :



index

每个模板都默认使用 layout 布局,您可在 front-matter 指定其他布局,或是设为 false 来关闭布局功能,您甚至可在布局中再使用其他布局来建立嵌套布局。

局部模板

局部模板让您在不同模板之间共享相同的组件,例如页首(Header)、页脚(Footer)或侧边栏(Sidebar)等,可利用局部模板功能分割为个别文件,让维护更加便利。举例来说:
{% codeblock partial/header.ejs %}

<%= config.title %>


{% endcodeblock %}

{% codeblock index.ejs %}
<%- partial('partial/header') %>

Home page

{% endcodeblock %}

生成:

My Site

Home page

局部变量

您可以在局部模板中指定局部变量并使用。
{% codeblock partial/header.ejs %}

<%= title>


{% endcodeblock %}

{% codeblock index.ejs %}
<%- partial('partial/header', {title: 'Hello World'}) %>

Home page

{% endcodeblock %}

生成:

Hello World

Home page

优化

如果您的主题太过于复杂,或是需要生成的文件量太过于庞大,可能会大幅降低性能,除了简化主题外,您可以考虑 Hexo 2.7 新增的局部缓存(Fragment Caching) 功能。

本功能借鉴于 Ruby on Rails,它储存局部内容,下次便能直接使用缓存内容,可以减少文件夹查询并使生成速度更快。

它可用于页首、页脚、侧边栏等文件不常变动的位置,举例来说:

<%- fragment_cache('header', function(){
  return '
'; });

如果您使用局部模板的话,可以更简单:

<%- partial('header', {}, {cache: true});

但是,如果您开启了 relative_link 参数的话,请勿使用局部缓存功能,因为相对链接在每个页面可能不同。

变量

这些变量很重要,因为将来自定义ejs,加入新的页面的时候,都需要了解这些变量

全局变量

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

网站变量

变量 描述
site.posts 所有文章
site.pages 所有分页
site.categories 所有分类
site.tags 所有标签

页面变量

变量 描述
site.posts 所有文章
site.pages 所有分页
site.categories 所有分类
site.tags 所有标签

A、页面

变量 描述
page.title 页面标题
page.date 页面建立日期(Moment.js 对象)
page.updated 页面更新日期(Moment.js 对象)
page.comments 留言是否开启
page.layout 布局名称
page.content 页面的完整内容
page.excerpt 页面摘要
page.more 除了页面摘要的其余内容
page.source 页面原始路径
page.full_source 页面的完整原始路径
page.path 页面网址(不含根路径)。我们通常在主题中使用 url_for(page.path)。
page.permalink 页面的完整网址
page.prev 上一个页面。如果此为第一个页面则为 null。
page.next 下一个页面。如果此为最后一个页面则为 null。
page.raw 文章的原始内容
page.photos 文章的照片(用于相簿)
page.link 文章的外部链接(用于链接文章)

B、文章

变量 描述
page.published 如果该文章已发布则为True
page.categories 该文章的所有分类
page.tags 该文章的所有标签

C、首页

变量 描述
page.per_page 每页显示的文章数量
page.total 总文章数
page.current 目前页数
page.current_url 目前分页的网址
page.posts 本页文章
page.prev 上一页的页数。如果此页是第一页的话则为 0。
page.prev_link 上一页的网址。如果此页是第一页的话则为 ''。
page.next 下一页的页数。如果此页是最后一页的话则为 0。
page.next_link 下一页的网址。如果此页是最后一页的话则为 ''。
page.path 当前页面的路径(不含根目录)。我们通常在主题中使用 url_for(page.path)。

D、归档

变量 描述
page.archive 等于 true
page.year 年份归档 (4位)
page.month 月份归档 (没有前导零的2位数)

E、分类

变量 描述
page.category 分类名称

F、标签

变量 描述
page.tag 标签名称

辅助函数

辅助函数帮助您在模版中快速插入内容。辅助函数不能在源文件中使用。

网址

A、url_for

在路径前加上根路径,从 Hexo 2.7 开始您应该使用此函数而不是 config.root + path

<%- url_for(path) %>

<%- url_for(/2017/02/20/HexoBlog/) %>

B、relative_url

取得与 from 相对的 to 路径。

<%- relative_url(from, to) %>

C、gravatar

插入 Gravatar 图片。
如果你不指定 options 参数,将会应用默认参数。否则,你可以将其设置为一个数字,这个数字将会作为 Gravatar 的大小参数。最后,如果你设置它一个对象,它将会被转换为 Gravatar 的一个查询字符串参数。

<%- gravatar(email, [options]) %>;

示例:

<%- gravatar('[email protected]') %>
// http://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787
<%- gravatar('[email protected]', 40) %>
// http://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40
<%- gravatar('[email protected]' {s: 40, d: 'http://example.com/image.png'}) %>
// http://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40&d=http%3A%2F%2Fexample.com%2Fimage.png

<%- gravatar('[email protected]') %>
<%- gravatar('[email protected]', 40) %>
<%- gravatar('[email protected]' {s: 40, d: 'http://example.com/image.png'}) %>

注意了没,这个不是在文中中使用的哦,这个是ejs模板语法,要在ejs模板文件中使用

HTML 标签

A、css

载入 CSS 文件。path 可以是数组或字符串,如果 path 开头不是 / 或任何协议,则会自动加上根路径;如果后面没有加上 .css 扩展名的话,也会自动加上。

<%- css(path, ...) %>

示例:

<%- css('style.css') %>
// 
<%- css(['style.css', 'screen.css']) %>
// 
// 

B、js

载入 JavaScript 文件。path 可以是数组或字符串,如果 path 开头不是 / 或任何协议,则会自动加上根路径;如果后面没有加上 .js 扩展名的话,也会自动加上。

<%- js(path, ...) %>

示例:

<%- js('script.js') %>
// 
<%- js(['script.js', 'gallery.js']) %>
// 
// 

C、link_to

插入链接。

<%- link_to(path, [text], [options]) %>
参数 描述 默认值
external 在新视窗打开链接 false
class Class 名称
id ID

示例:

<%- link_to('http://www.google.com') %>
// http://www.google.com
<%- link_to('http://www.google.com', 'Google') %>
// Google
<%- link_to('http://www.google.com', 'Google', {external: true}) %>
// Google

D、mail_to

插入电子邮箱链接。

<%- mail_to(path, [text], [options]) %>
参数 描述
class Class 名称
id ID
subject 邮件主题
cc 抄送(CC)
bcc 密送(BCC)
body 邮件内容

示例:

<%- mail_to('[email protected]') %>
// [email protected]
<%- mail_to('[email protected]', 'Email') %>
// Email

E、image_tag

插入图片。

<%- image_tag(path, [options]) %>
参数 描述
alt 图片的替代文字
class Class 名称
id ID
width 图片宽度
height 图片高度

F、favicon_tag

插入favicon。

<%- favicon_tag(path) %>

G、feed_tag

插入 feed 链接。

<%- feed_tag(path, [options]) %>
参数 描述 默认值
title Feed 标题
type Feed 类型 atom

条件函数

A、is_current

检查 path 是否符合目前页面的网址。开启 strict 选项启用严格比对。

<%- is_current(path, [strict]) %>

B、is_home

检查目前是否为首页。

<%- is_home() %>

C、is_post

检查目前是否为文章。

<%- is_post() %>

D、is_archive

检查目前是否为存档页面。

<%- is_archive() %>

E、is_year

检查目前是否为年度归档页面。

<%- is_year() %>

F、is_month

检查目前是否为月度归档页面。

<%- is_month() %>

G、is_category

检查目前是否为分类归档页面。
如果给定一个字符串作为参数,将会检查目前是否为指定分类。

<%- is_category() %>
<%- is_category('hobby') %>

H、is_tag

检查目前是否为标签归档页面。
如果给定一个字符串作为参数,将会检查目前是否为指定标签。

<%- is_tag() %>
<%- is_tag('hobby') %>

字符串处理

A、trim

清除字符串开头和结尾的空格。

<%- trim(string) %>

B、strip_html

清除字符串中的 HTML 标签。

<%- strip_html(string) %>

示例:

<%- strip_html('It's not important anymore!') %>
// It's not important anymore!

C、titlecase

把字符串转换为正确的 Title case。

<%- titlecase(string) %>

示例:

<%- titlecase('this is an apple') %>
#   This is an Apple

D、markdown

使用 Markdown 解析字符串。

<%- markdown(str) %>

示例:

<%- markdown('make me **strong**') %>
// make me strong

E、render

解析字符串。

<%- render(str, engine, [options]) %>

F、word_wrap

使每行的字符串长度不超过 length。length 预设为 80。

<%- word_wrap(str, [length]) %>

示例:

<%- word_wrap('Once upon a time', 8) %>
// Once upon\n a time

G、truncate

移除超过 length 长度的字符串。

<%- truncate(text, length) %>

示例:

<%- truncate('Once upon a time in a world far far away', {length: 17}) %>
// Once upon a ti...
<%- truncate('Once upon a time in a world far far away', {length: 17, separator: ' '}) %>
// Once upon a...
<%- truncate('And they found that many people were sleeping better.', {length: 25, omission: '... (continued)'}) %>
// And they f... (continued)

模板

A、partial

载入其他模板文件,您可在 locals 设定区域变量。

<%- partial(layout, [locals], [options]) %>
参数 描述 默认值
cache 缓存(使用 Fragment cache) false
only 限制局部变量。在模板中只能使用 locals 中设定的变量。 false

B、fragment_cache

局部缓存。它储存局部内容,下次使用时就能直接使用缓存。

<%- fragment_cache(id, fn);

示例:

<%- fragment_cache('header', function(){
  return '
'; }) %>

日期与时间

date

插入格式化的日期。date 可以是 UNIX 时间、ISO 字符串、Date 对象或 Moment.js 对象。format 默认为 date_format 配置信息。

<%- date(date, [format]) %>

示例:

<%- date(Date.now()) %>
// 2013-01-01
<%- date(Date.now(), 'YYYY/M/D') %>
// Jan 1 2013

date_xml

插入 XML 格式的日期。date 可以是 UNIX 时间、ISO 字符串、Date 对象或 Moment.js 对象。

<%- date_xml(date) %>

示例:

<%- date_xml(Date.now()) %>
// 2013-01-01T00:00:00.000Z

time

插入格式化的时间。date 可以是 UNIX 时间、ISO 字符串、Date 对象或 Moment.js 对象。format 默认为 time_format 配置信息。

<%- time(date, [format]) %>

示例:

<%- time(Date.now()) %>
// 13:05:12
<%- time(Date.now(), 'h:mm:ss a') %>
// 1:05:12 pm

full_date

插入格式化的日期和时间。date 可以是 UNIX 时间、ISO 字符串、Date 对象或 Moment.js 对象。format 默认为 date_format + time_format。

<%- full_date(date, [format]) %>

示例:

<%- full_date(new Date()) %>
// Jan 1, 2013 0:00:00
<%- full_date(new Date(), 'dddd, MMMM Do YYYY, h:mm:ss a') %>
// Tuesday, January 1st 2013, 12:00:00 am

moment

Moment.js 函数库。

列表

list_categories

插入分类列表。

<%- list_categories([options]) %>
参数 描述 默认值
orderby 分类排列方式 name
order 分类排列顺序。1, asc 升序;-1, desc 降序。 1
show_count 显示每个分类的文章总数 true
style 分类列表的显示方式。使用 list 以无序列表(unordered list)方式显示。 list
separator 分类间的分隔符号。只有在 style 不是 list 时有用。 ,
depth 要显示的分类层级。0 显示所有层级的分类;-1 和 0 很类似,但是显示不分层级;1 只显示第一层的分类。 0
class 分类列表的 class 名称。 category
transform 改变分类名称显示方法的函数

list_tags

插入标签列表。

<%- list_tags([options]) %>
参数 描述 默认值
orderby 标签排列方式 name
order 标签排列顺序。1, asc 升序;-1, desc 降序。 1
show_count 显示每个标签的文章总数 true
style 标签列表的显示方式。使用 list 以无序列表(unordered list)方式显示。 list
separator 标签间的分隔符号。只有在 style 不是 list 时有用。
class 标签列表的 class 名称。 tag
transform 改变标签名称显示方法的函数
amount 要显示的标签数量(0 = 无限制) 0

list_archives

插入归档列表。

<%- list_archives([options]) %>
参数 描述 默认值
type 类型。此设定可为 yearly 或 monthly。 monthly
order 排列顺序。1, asc 升序;-1, desc 降序。 1
show_count 显示每个归档的文章总数 true
format 日期格式 MMMM YYYY
style 归档列表的显示方式。使用 list 以无序列表(unordered list)方式显示。 list
separator 归档间的分隔符号。只有在 style 不是 list 时有用。
class 归档列表的 class 名称。 archive
transform 改变归档名称显示方法的函数

list_posts

插入文章列表。

<%- list_posts([options]) %>
参数 描述 默认值
orderby 文章排列方式 date
order 文章排列顺序。1, asc 升序;-1, desc 降序。 -1
style 文章列表的显示方式。使用 list 以无序列表(unordered list)方式显示。 list
separator 文章间的分隔符号。只有在 style 不是 list 时有用。
class 文章列表的 class 名称。 post
amount 要显示的文章数量(0 = 无限制) 6
transform 改变文章名称显示方法的函数

tagcloud

插入标签云。

<%- tagcloud([tags], [options]) %>
参数 描述 默认值
min_font 最小字体尺寸 10
max_font 最大字体尺寸 20
unit 字体尺寸的单位 px
amount 标签总量 40
orderby 标签排列方式 name
order 标签排列顺序。1, sac 升序;-1, desc 降序 1
color 使用颜色 false
start_color 开始的颜色。您可使用十六进位值(#b700ff),rgba(rgba(183, 0, 255, 1)),hsla(hsla(283, 100%, 50%, 1))或 颜色关键字。此变量仅在 color 参数开启时才有用。
end_color 结束的颜色。您可使用十六进位值(#b700ff),rgba(rgba(183, 0, 255, 1)),hsla(hsla(283, 100%, 50%, 1))或 颜色关键字。此变量仅在 color 参数开启时才有用。

其他

paginator

插入分页链接。

<%- paginator(options) %>
参数 描述 默认值
base 基础网址 /
format 网址格式 page/%d/
total 分页总数 1
current 目前页数 0
prev_text 上一页链接的文字。仅在 prev_next 设定开启时才有用。 Prev
next_text 下一页链接的文字。仅在 prev_next 设定开启时才有用。 Next
space 空白文字 …
prev_next 显示上一页和下一页的链接 true
end_size 显示于两侧的页数 1
mid_size 显示于中间的页数 2
show_all 显示所有页数。如果开启此参数的话,end_size 和 mid_size 就没用了。 false

search_form

插入 Google 搜索框。

<%- search_form(options) %>
参数 描述 默认值
class 表单的 class name search-form
text 搜索提示文字 Search
button 显示搜索按钮。此参数可为布尔值(boolean)或字符串,当设定是字符串的时候,即为搜索按钮的文字。 false

number_format

格式化数字。

<%- number_format(number, [options]) %>
参数 描述 默认值
precision 数字精度。此选项可为 false 或非负整数。 false
delimiter 千位数分隔符号 ,
separator 整数和小数之间的分隔符号 ,

示例:

<%- number_format(12345.67, {precision: 1}) %>
// 12,345.68
<%- number_format(12345.67, {precision: 4}) %>
// 12,345.6700
<%- number_format(12345.67, {precision: 0}) %>
// 12,345
<%- number_format(12345.67, {delimiter: ''}) %>
// 12345.67
<%- number_format(12345.67, {separator: '/'}) %>
// 12,345/67

open_graph

插入 open graph 资源。

<%- open_graph([options]) %>
参数 描述 默认值
title 页面标题 (og:title) page.title
type 页面类型 (og:type) blog
url 页面网址 (og:url) url
image 页面图片 (og:image) 内容中的图片
site_name 网站名称 (og:site_name) config.title
description 页面描述 (og:desription) 内容摘要或前 200 字
twitter_card Twitter 卡片类型 (twitter:card) summary
twitter_id Twitter ID (twitter:creator)
twitter_site Twitter 网站 (twitter:site)
google_plus Google+ 个人资料链接
fb_admins Facebook 管理者 ID
fb_app_id Facebook 应用程序 ID

last: toc

解析内容中的标题标签 (h1~h6) 并插入目录。

<%- toc(str, [options]) %>
参数 描述 默认值
class Class 名称 toc
list_number 显示编号 true

示例:

<%- toc(page.content) %>

Hexo页面渲染流程

Yelee目录说明

看一下,Yelee主题的文件目录:

搭建Hexo博客进阶篇---主题自定义(三)_第1张图片

根据这个目录我们来分析Hexo是如何工作的
我们都知道两个命名,一个是 hexo new page name ,一个是 hexo new post name

  • hexo new page name
    创建一个新页面 , 页面具体渲染模板在Theme主题下的layout文件夹下面

  • hexo new post name/hexo new post draft
    是创建一篇新文章,新文章保存在source/_posts目录下,如果是hexo new draft name,则是保存在source/_drafts目录下,那么根据scaffolds的模板,可以确定新建的文章或者草稿的基本配置

看下图:

搭建Hexo博客进阶篇---主题自定义(三)_第2张图片

下面看一下我们的,引擎模板文件:
入口模板

搭建Hexo博客进阶篇---主题自定义(三)_第3张图片

具体实现

搭建Hexo博客进阶篇---主题自定义(三)_第4张图片

想要自定义404吗?想要写一个个性化的about me吗?想要实现完全自定义吗?哈哈这个你还是得去学习 EJS

如何实现用D3-cloud来展现标签云

有没有感觉 Hexo 自带的 tag-cloud 标签云太丑陋了呢!作为一个前端程序员,对审美可是有着比较高的要求,
github 上面有 d3-cloud 这个项目,那么我们来玩一玩吧,把github上的d3-cloud项目在我们的hexo博客中使用哈!
hexo是静态博客,所以最后在网上看到的都是静态的内容,也就是说,我们的看到的标签云也是静态的已经生成好的内容,并不会随着刷新页面而重新计算生成另外样式的标签云。
当然d3-cloud这个项目,提供了浏览器端和node端运行的版本,见它的例子,我们可以在客户端运行,也可以在服务端作为 node运行。

具体操作流程

  1. 找到关于tagcloud模板文件以及JS和CSS
    我上面说的,应该很容易找到吧,我已经找到了呀

  2. 安装模块

    npm install canvas --save
    npm install d3-cloud --save
    npm install d3 --save
  3. 找到文件: 你的 blog项目 -> node_modules -> hexo ->plugins -> helper -> index.js

    var tagcloud = require('./tagcloud');
    helper.register('tagcloud', tagcloud);
    helper.register('tag_cloud', tagcloud);
    ​
    //修改为下面的代码:目的是不直接修改tagcloud.js,保留代码
    var tagcloud = require('./tagcloud');
    var tagcloudd3 = require('./tagcloudd3');
    helper.register('tagcloud', tagcloudd3);
    helper.register('tag_cloud', tagcloudd3);
  4. 新建文件tagcloudd3.js :位置在blog项目 -> node_modules -> hexo ->plugins -> helper -> tagcloudd3.js
    tagcloud3.js的内容如下:

    'use strict';
    ​    
    var Canvas = require("canvas");
    var cloud = require("d3-cloud");
    var d3 = require("d3");
    ​    
    var layout = cloud()//利用d3-cloud计算每个标签的位置
        .size([600, 400])
        .canvas(function() { return new Canvas(1, 1); })
        .padding(7)
        .rotate(function() { return ~~(Math.random() * 2) * 90; })
        .font("Impact")
        .fontSize(function(d) { return d.size; });
    var fill = d3.scale.category20();//利用d3的接口给每个标签颜色
    ​
    function tagcloudHelper(tags){
      /****与tagcloud.js一样,获得tags 开始***/
      if ((!tags || !tags.hasOwnProperty('length'))){
        tags = this.site.tags;
      }
    ​
      if (!tags || !tags.length) return '';
     
    var result = [];
    ​
    tags = tags.sort('name', 1);
    ​
    // Ignore tags with zero posts
    tags = tags.filter(function(tag){
    return tag.length;
    });
     /****与tagcloud.js一样,获得tags 结束***/
     
    //计算标签出现次数最大值,比如,博客中一共有两个标签,一个是hello,一个是world,hello出现2次,world 出现1次,那么maxsize就是2
    var maxsize = 1;
    ​
    tags.sort('length').forEach(function(tag){
    var length = tag.length;
    if(length > maxsize)
        maxsize = length;
    });
    ​
     //构建传入layout的words
    var arr = [],words;
    tags.forEach(function(tag){
     arr.push({"name": tag.name,"num" : tag.length});
    });
    words = arr.map(function(d) {
      var text = d.name.replace(/[^\x00-\xff]/g,"ab");//对中文的投机处理,用ab代替中文字符
      return {name:d.name, text: text, size : Math.log(d.num)/(Math.log(maxsize)-Math.log(1)) * 15 + 30};//size的计算取对数,是为了让标签之间的大小相对平均一些。因为博客侧重前端内容,所以某一些标签会比较多,标签最大最小次数的差距会比较大。
     
    });
    layout.words(words);
    layout.start();
    ​
    result.push('');
    words.forEach(function(word,i){
    ​
    result.push(
      ''+
        word.name+
      ''
    );
    });
    result.push('');
     
    return result.join('');
     
    }
    module.exports = tagcloudHelper;
  5. 运行,就可以看到结果啦
    这个我并没有实际操作,原因很简单,最近比较忙,还有一个就是,node安装canvas实在是太麻烦了呀,

这里给出地址:

  • 如何用npm install canvas?

  • npm install canvas

Yelee 主题配置

关于主题的配置,这篇文章讲的很详细啦,Yelee中文参考手册

关于Hexo,还有最后一篇文章,请看 :搭建Hexo博客进阶篇--API和一些小部件

参考资料

  1. Hexo官方网站 : https://hexo.io/

  2. 利用d3-cloud实现标签云 : http://www.cnblogs.com/lilyimage/p/5207697.html

你可能感兴趣的:(博客搭建,hexo)