基于Hexo-Ocean主题博客搭建

本文主要是Hexo Ocean主题博客搭建过程的记录
博客地址:松林羊

hexo 的基本命令

hexo init [folder] :创建一个存放网站源码的文件夹。
hexo new [layout] <title>:新建一篇文章。layout:默认post,可以是page、draft。title:文章标题,标题包含空格的话,请使用引号括起来。
hexo clean:清除缓存文件db.json和已生成的静态文件public,尤其是更换主题后
hexo g:生成静态html文件
hexo s:启动服务器
hexo d:部署网站
传送门:
官方文档

下载主题源码

在hexo init [folder] 的folder目录下执行:

1
git clone https://github.com/zhwangart/hexo-theme-ocean.git themes/ocean

参照主题文档进行配置

Ocean 中文文档
关于 Ocean 使用中的问题

文章自动添加Read More

将themesoceanlayout_partialarticle.ejs文中的<% if (post.excerpt && index){ %>的else部分替换为如下内容:

1
2
3
4
5
6
7
8
9
<% var br = post.content.indexOf('<br>') %>
<% if(br < 0 || !index) { %>
<%- post.more %>
<% } else { %>
<%- post.content.substring(0, br) %><br/>
<% if (theme.excerpt_link) { %>
<a class="article-more-link" href="<%- url_for(post.path) %>"><%= theme.excerpt_link %></a>
<% } %>
<% } %>

搜索功能不起作用? or 除开首页不能正常搜索

  1. 本地检索需要安装插件

    1
    npm install hexo-generator-searchdb --save
  2. 另外一个问题:插件搜索函数返回的url 地址有问题 ,作者说是因为 “中文字符被URL encode了 ” 。后来我找到一个解决办法:
    将 [folder]/node_modules/hexo-generator-searchdb/templates/xml.ejs 文件中的:

    1
    <url><%- encodeURIComponent(config.root + post.path) %></url>

    修改为

    1
    <url><%- encodeURI(config.root + post.path) %></url>

修改导航栏

修改 themes/ocean/source/css/_partial/navbar.styl 文件

文章添加封面图片

1
2
3
4
5
6
7
8
---
title: Post name
date: 2019-07-24 22:01:03
photos: [
["/images/相机.jpg"], // themes/ocean/source/images目录下
["https://tuchong.pstatp.com/2716763/f/531173888.jpg"]
]
---

在首页只会显示第一张,详情页会按顺序显示这两张

为文章添加Gitalk评论

参考:https://zhwangart.github.io/2018/12/06/Gitalk/

在右上角或者左上角实现fork me on github

选样式:GitHub Corners-1GitHub Corners-2
然后粘贴刚才复制的代码到themes/ocean/layout/index.ejs文件中,放在<div id=”landingpage”></div>的第一行,并把href改为你的github地址
对样式做出修改:
<div id=”landingpage”> 修改为 <div id=”landingpage” style=”position:relative;”>
复制的<a>标签添加如下样式:style=”position:absolute;left:0;top:100;z-index=1000;”

实现点击出现特效

  1. 点击桃心
    下载:
    桃心Js
    然后将里面的代码copy一下,新建love.js文件并且将代码复制进去,然后保存。
    在themes/ocean/_config.yml最后一行写入:

    1
    lovejs: true

    将love.js文件放到路径/themes/ocean/source/js/src里面,然后打开themesoceanlayout_partial after-footer.ejs文件, 在最后一行写入:

    1
    2
    3
    <% if (theme.lovejs){ %>
    <%- js('/js/love.js') %>
    <% } %>
  2. 爆炸效果
    下载:fireworks.jsanime.min.js
    步骤与上面类似保存js到/themes/ocean/source/js/src,最后在themesoceanlayout_partial after-footer.ejs文件内容未写入:

    1
    2
    3
    4
    5
    <% if (theme.fireworks){ %>
    <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas>
    <%- js('/js/anime.min.js') %>
    <%- js('/js/fireworks.js') %>
    <% } %>

头像旋转效果

打开themesoceanlayout_partialsidebar.ejs,给<div class=logo>下的img加上一个id。然后参考:css + js实现图片不停旋转 鼠标悬停停止旋转
然后将里面的js代码copy到一个my.js文件中(注意替换img的id),保存到/themes/ocean/source/js/src目录。
然后在themesoceanlayout_partialafter-footer.ejs中最后一行写入:

1
<%- js('/js/my.js') %>

网站底部加上访问量

themesoceanlayout_partialafter-footer.ejs 中默认是导入了统计脚本的(busuanzi-2.3.pure.min.js )

修改访问量统计的样式:
将themesoceanlayout_partialpostbusuanzi.ejs
修改为:

1
2
3
4
5
6
7
8
9
<div class="powered-by">
<% if (is_home()) { %>
<span id="busuanzi_container_site_pv">访问量:<span id="busuanzi_value_site_pv"></span></span>
<%} %>
&emsp;<i class="fa fa-user-md"></i><span id="busuanzi_container_site_uv">访客数:<span id="busuanzi_value_site_uv"></span></span>&emsp;
<% if (is_post()) { %>
<i class="fe fe-bookmark"></i>文章访问量:<span id="busuanzi_value_page_pv"></span>
<%} %>
</div>

添加网站字数,阅读时间统计

在根目录下运行:

1
npm install hexo-wordcount –save

在themesocean_config.yml主题配置文件中加入:

1
2
3
4
5
6
post_wordcount:
item_text: true
wordcount: true
min2read: true
totalcount: true
separated_meta: true

在themesoceanlayout_partialfooter.ejs文件中,在<ul class=”list-inline”>标签后加入:

1
2
3
<ul class="list-inline">
<li>全站共<span class="post-count"><%= totalcount(site) %></span></li>
</ul>

在themesoceanlayout_partialarticle.ejs文件中,在

1
2
&emsp;<i class="fe fe-bar-chart"></i> <span class="post-count"><%- wordcount(post.content) %></span>
&emsp;<i class="fe fe-clock"></i> <span class="post-count"><%- min2read(post.content) %></span>分钟

Ocean主题的图标

图标在themesoceansourcecss_feathericon.styl中查找
官网:
feathericons

为博客加上萌萌的宠物

hexo-helper-live2d
在网站根目录下执行

1
2
npm install -save hexo-helper-live2d
npm install live2d-widget-model-haruto(自己选择的萌宠模型)

在hexo的配置文件中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 萌宠
live2d:
enable: true
scriptFrom: local
model:
use: live2d-widget-model-haruto
scale: 1
hHeadPos: 0.5
vHeadPos: 0.618
display:
superSample: 2
width: 150
height: 300
position: left
hOffset: 0
vOffset: -20
mobile:
show: true
react:
opacityDefault: 0.5
opacityOnHover: 0.2

重启服务:

1
hexo clean && hexo g && hexo s

添加网站运行时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
<script>
var now = new Date();
function () {
var grt= new Date("04/26/2019 15:49:00");
now.setTime(now.getTime()+250);
days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours);
if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;}
seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;}
document.getElementById("timeDate").innerHTML = "本站已安全运行 "+dnum+" 天 ";
document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
}
setInterval("createtime()",250);
</script>

将以上代码保存到themesoceanlayout_partialpostruntime.ejs

在themesoceanlayout_partialfooter.ejs文件中,第一个<ul class=”list-inline”></ul>标签后加入:

1
2
3
<div class="float-right">
<%- partial('post/runtime') %>
</div>

添加DaoVoice 在线联系

首先在https://account.daocloud.io/signin  注册账号
然后点击下方链接
http://dashboard.daovoice.io/get-started?invite_code=0f81ff2f
之后会得到一个app_id

在主题配置文件写入:

1
2
3
# Online contact 
daovoice: true
daovoice_app_id: 这里填你的刚才获得的 app_id

在themesoceanlayout_partialfooter.ejs中,</head>前写入:

1
2
3
4
5
6
7
8
9
<% if (theme.daovoice){ %>
<script>
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/0f81ff2f.js","daovoice")
daovoice('init', {
app_id: "<%- theme.daovoice_app_id %>"
});
daovoice('update');
</script>
<% } %>

取消文章下面的分享连接,添加本文结束

去掉themesoceanlayout_partialarticle.ejs中的以下代码:

1
<a data-url="<%- post.permalink %>" data-id="<%= post._id %>" class="article-share-link"><%- theme.share_text %></a>

同时还可以添加本文结束 感谢阅读等说明:
如在<%- partial(‘post/tag’) %>下面一行添加:

1
2
3
<% if (!index && is_post()) { %>
<div style="text-align:center;color: #ccc;font-size:14px;">------------- 本文结束&nbsp;<i class="fe fe-smile"></i>&nbsp;感谢您的阅读 -------------</div>
<% } %>

博文压缩

在根目录下执行:

1
2
npm install gulp -g
npm install gulp-minify-css gulp-uglify gulp-htmlmin gulp-htmlclean gulp –save

在根目录下新建gulpfile.js,写入一下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var gulp = require('gulp');
//Plugins模块获取
var minifycss = require('gulp-minify-css');
var uglify = require('gulp-uglify');
var htmlmin = require('gulp-htmlmin');
var htmlclean = require('gulp-htmlclean');
//压缩css
gulp.task('minify-css',
function() {
return gulp.src('./public/**/*.css').pipe(minifycss()).pipe(gulp.dest('./public'));
});
//压缩html
gulp.task('minify-html',
function() {
return gulp.src('./public/**/*.html').pipe(htmlclean()).pipe(htmlmin({
removeComments: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}))
.pipe(gulp.dest('./public'))
});
//压缩js 不压缩min.js
gulp.task('minify-js',
function() {
return gulp.src(['./public/**/*.js', '!./public/**/*.min.js']).pipe(uglify()).pipe(gulp.dest('./public'));
});

//4.0以前的写法
//gulp.task('default', [
// 'minify-html', 'minify-css', 'minify-js'
//]);

//4.0以后的写法
// 执行 gulp 命令时执行的任务
//gulp.task('default', gulp.parallel('minify-html', 'minify-css', 'minify-js',
//function() {
// Do something after a, b, and c are finished.
// console.log('success')
//}));

gulp.task('default',gulp.series(gulp.parallel('minify-html','minify-css','minify-js')));

生成博文时执行

1
hexo clean && hexo g && gulp && hexo d

就会根据 gulpfile.js 中的配置,对 public 目录中的静态资源文件进行压缩。

修改文章封面图片的引入方式,同时支持相对地址与http的图片

将themesoceanlayout_partialpostgallery.ejs
中的<% if (index){ %>的上一行写入:

1
<% var idx = url_for(photo).indexOf('http') %>

将文中两处的:

1
<img src="<%- url_for(photo) %>" itemprop="image">

修改为:

1
2
3
4
5
<% if(idx < 0) { %>
<img src="<%- url_for(post.path)+url_for(photo).substring(1) %>" itemprop="image">
<% } else { %>
<img src="<%- url_for(photo) %>" itemprop="image">
<% } %>

设置封面图片不在内容详情页展示

将themesoceanlayout_partialarticle.ejs
中的

1
<%- partial('post/gallery') %>

修改为:

1
2
3
<% if (index){ %>
<%- partial('post/gallery') %>
<% } %>

去掉rss订阅

根目录下执行:

1
npm uninstall hexo-generator-feed –save

将themesocean_config.yml文件中修改为:rss: false

导航栏图表改为在文字左侧

修改themesoceansourcecss_partialnavbar.styl

1
2
3
4
5
6
7
&.nav-main
.nav-item-link
&::before, i.fe
display block
line-height 1
&::before
font-family 'feathericon'

修改为:

1
2
3
4
5
6
7
8
&.nav-main
.nav-item-link
&::before, i.fe
// display block
line-height 1
margin-right: 10px;
&::before
font-family 'feathericon'

添加readme.md不被渲染

在Hexo目录下的source根目录下添加一个, README.md。
修改Hexo目录下的_config.yml。
将skip_render参数的值设置上。skip_render: README.md
保存退出即可。

首页视屏换成图片

将themesoceanlayout_partialocean.ejs中

1
2
3
4
5
6
7
<video playsinline="" autoplay="" loop="" muted="" data-autoplay=""
poster="<%- theme.ocean.path %>ocean.png" x5-video-player-type="h5">
<source src="<%- theme.ocean.path %>ocean.mp4" type="video/mp4">
<source src="<%- theme.ocean.path %>ocean.ogv" type="video/ogg">
<source src="<%- theme.ocean.path %>ocean.webm" type="video/webm">
<p>Your user agent does not support the HTML5 Video element.</p>
</video>

修改为:

1
<img src="<%- theme.ocean.path %>ocean.png">

去掉首页视频或图片

去掉themes/ocean/layout/index.ejs中的

1
<%- partial('_partial/ocean') %>

is_home()、is_post() 函数判断不正确

将themesoceanlayoutlayout.ejs中

1
<%- partial('_partial/footer', null, {cache: !config.relative_link}) %>

修改为

1
<%- partial('_partial/footer', null, {cache: config.relative_link}) %>

就是将partial中的cache设置为false。参考:is_home()、is_post() 函数判断不正确

视频 or 图片只在pc端显示,不在移动端显示

修改themesoceansourcecss_partiallayou.styl文件

1
2
3
4
5
// Media Query
@media (min-width: 768px)
.jumbotron
margin-bottom 6rem
display block //此处为新增。设备宽度大于等于768像素时显示视频or图片

在文件末尾新增

1
2
3
@media (max-width: 768px)
.jumbotron
display none // 设备宽度小于等于768像素时不显示视频or图片

此时会发现移动端左上角有点空旷,则进行如下修改
修改themesoceanlayout_partialarchive.ejs文件

1
2
3
4
5
var title = '';
var mobile_title = "松林羊 Blog"; // 此处为新增
...
<h1 class="page-type-title pc"><%- title %></h1> // 新增类名为pc的样式
<h1 class="page-type-title mobile"><%- mobile_title %></h1> // 此处为新增

修改themesoceansourcecss_partialarchive.styl文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.page-type-title
margin 0
padding 3rem 0
// 以下内容为新增
&.pc
@media screen and (max-width: 768px)
display none
@media screen and (min-width: 768px)
display block
&.mobile
@media screen and (max-width: 768px)
display block
font-family 'STXingkai'
@media screen and (min-width: 768px)
display none

配置fancybox展示文章图集

在themesoceanlayout_partialafter-footer.ejs文件末尾加入如下代码

1
2
3
4
5
6
7
8
<% if (is_post()){ %>
<script>
// 使用fancybox来显示post图片集(#andus-head-img为头像id)
$('img:not(#andus-head-img)').each(function() {
$(this).wrap('<a class="fancybox" data-fancybox="gallery" href="' + $(this).prop("src") + '"></a>');
})
</script>
<% } %>

更换评论系统,由gitalk跟换为valine, 并增加邮件通知功能

依次参考
Valine–一款极简的评论系统
Valine
Valine-Admin
themes/ocean/_config.yml文件中新增以下内容,同时确保gitalk.enablefalse

1
2
3
4
5
6
7
8
9
10
11
# Valine 不能与gitalk同时开启
valine:
enable: true
app_id: # 这里填写得到的APP ID
app_key: # 这里填写得到的APP KEY
placeholder: 记得留下你的昵称和邮箱...可以快速收到回复ヾノ≧∀≦)o # [v1.0.7 new]留言框占位提示文字
notify: true # 评论回复邮件提醒 。 第三方支持:https://github.com/zhaojun1998/Valine-Admin
verify: false # 验证码 。 开启邮件提醒会默认开启验证码选项
avatar: monsterid # Gravatar头像。可选项:[identicon monsterid wavatar retro robohash mp ''] ,见 https://valine.js.org/avatar.html
recordIP: true # 是否记录评论者ip
visitor: false # 阅读量统计 https://valine.js.org/visitor.html

拷贝themesoceanlayout_partialpostgitalk.ejs重命名为valine.ejs
全部内容修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<% if (theme.valine.enable) { %>
<div class="comment_headling" style="margin-top:5rem;">
<font size="5"><i class="fe fe-comments"></i> 评论</font>
</div>
<div class="comment"></div>
<%- js('https://cdn1.lncld.net/static/js/3.0.4/av-min.js') %>
<%- js('js/Valine.min.js') %>
<script type="text/javascript">
// https://cdnjs.cloudflare.com/ajax/libs/valine/1.3.10/Valine.min.js
GUEST_INFO = ["nick", "mail", "link"],
guest_info = "nick,mail,link".split(",").filter(function(i) {
return - 1 < GUEST_INFO.indexOf(i)
});
guest_info = 0 == guest_info.length ? GUEST_INFO: guest_info,
new Valine({
// AV 对象来自上面引入av-min.js
av: AV,
el: '.comment',
app_id: '<%- theme.valine.app_id %>',
app_key: '<%- theme.valine.app_key %>',
placeholder: '<%- theme.valine.placeholder %>',
meta: guest_info,
notify: <%- theme.valine.notify %>,
verify: <%- theme.valine.verify %>,
avatar: '<%- theme.valine.avatar %>',
recordIP: <%- theme.valine.recordIP %>,
visitor: <%- theme.valine.visitor %>,
lang: 'zh-cn'
});
</script>
<% } %>

修改themesoceanlayout_partialarticle.ejs文件

1
2
3
4
5
<% if (is_post()) { %>
<%- partial('post/gitalk') %>
<%# 下面为新增内容 %>
<%- partial('post/valine') %>
<%} %>

关闭评论时的验证码,将Valine.min.js保存到themesoceansourcejs目录下,将其中

1
2
3
4
5
6
7
8
u.attr(Q, "style", "display:block;"), t && t.type) {
var o = u.find(Q, ".vsure");
u.on("click", o,
function(n) {
e.alert.hide(),
t.cb && t.cb()
})
}

修改为

1
2
3
4
u.attr(Q, "style", "display:none;"), t && t.type) {
e.alert.hide(),
t.cb && t.cb()
}
记录(自用)
1
2
<%- page.content.substring(0,tips) %> 显示html的样式结果
<%= page.content.substring(0,tips) %>显示html源代码