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

本文续接 Hexo 文档讲解篇

Yelee主题介绍

更换主题

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

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

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

  1. Layout

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

    layout.ejs   - 使用 EJS
    layout.swig  - 使用 Swig
    

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

  1. 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 %}
<!DOCTYPE html>
<html>
<body><%- body %></body>
</html>
{% endcodeblock %}

生成 :

<!DOCTYPE html>
<html>
<body>index</body>
</html>

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

局部模板

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

{% codeblock partial/header.ejs %}
<h1 id="logo"><%= config.title %></h1>
{% endcodeblock %}

{% codeblock index.ejs %}
<%- partial('partial/header') %>
<div id="content">Home page</div>
{% endcodeblock %}

生成:

<h1 id="logo">My Site</h1>
<div id="content">Home page</div>

局部变量

您可以在局部模板中指定局部变量并使用。

{% codeblock partial/header.ejs %}
<h1 id="logo"><%= title></h1>
{% endcodeblock %}

{% codeblock index.ejs %}
<%- partial('partial/header', {title: 'Hello World'}) %>
<div id="content">Home page</div>
{% endcodeblock %}

生成:

<h1 id="logo">Hello World</h1>
<div id="content">Home page</div>

优化

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

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

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

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

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

<%- 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('a@abc.com') %>
// http://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787
<%- gravatar('a@abc.com', 40) %>
// http://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40
<%- gravatar('a@abc.com' {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('a@abc.com') %>
<%- gravatar('a@abc.com', 40) %>
<%- gravatar('a@abc.com' {s: 40, d: 'http://example.com/image.png'}) %>

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

HTML 标签

A、css

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

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

示例:

<%- css('style.css') %>
// <link rel="stylesheet" href="/style.css" type="text/css">
<%- css(['style.css', 'screen.css']) %>
// <link rel="stylesheet" href="/style.css" type="text/css">
// <link rel="stylesheet" href="/screen.css" type="text/css">

B、js

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

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

示例:

<%- js('script.js') %>
// <script type="text/javascript" src="/script.js"></script>
<%- js(['script.js', 'gallery.js']) %>
// <script type="text/javascript" src="/script.js"></script>
// <script type="text/javascript" src="/gallery.js"></script>

C、link_to

插入链接。

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

示例:

<%- link_to('http://www.google.com') %>
// <a href="http://www.google.com" title="http://www.google.com">http://www.google.com</a>
<%- link_to('http://www.google.com', 'Google') %>
// <a href="http://www.google.com" title="Google">Google</a>
<%- link_to('http://www.google.com', 'Google', {external: true}) %>
// <a href="http://www.google.com" title="Google" target="_blank" rel="external">Google</a>

D、mail_to

插入电子邮箱链接。

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

示例:

<%- mail_to('a@abc.com') %>
// <a href="mailto:a@abc.com" title="a@abc.com">a@abc.com</a>
<%- mail_to('a@abc.com', 'Email') %>
// <a href="mailto:a@abc.com" title="Email">Email</a>

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 <b>important</b> 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>strong</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 '<header></header>';
}) %>

日期与时间

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是如何工作的
我们都知道两个命名,一个是 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的模板,可以确定新建的文章或者草稿的基本配置
    看下图:
原理

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

入口模板

具体实现

实现过程

想要自定义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);
```

  1. 新建文件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('<svg width="600" height="400"><g transform="translate(300,200)">');
     words.forEach(function(word,i){
         result.push(
         '<text text-anchor="middle" fill="'+fill(i)+'" transform="translate('+word.x+','+word.y+')rotate('+
         word.rotate+')" style="font-size:'+word.size+'px;font-family:Impact">'+word.name+'</text>'
         );
     });
     result.push('</g></svg>');
     return result.join('');         
     }
     module.exports = tagcloudHelper;
    
  2. 运行,就可以看到结果啦
    这个我并没有实际操作,原因很简单,最近比较忙,还有一个就是,node安装canvas实在是太麻烦了呀,
    这里给出地址:

Yelee 主题配置

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

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

参考资料

  1. Hexo官方网站 : https://hexo.io/
  2. 利用d3-cloud实现标签云 : http://www.cnblogs.com/lilyimage/p/5207697.html
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容