老实说,其实为什么突然又开始折腾折腾主题了呢…….因为用NexT的人实在太多了。而我又不想让别人打开发现“和某个某个人的很像”。那样就失去了折腾的必要。因此我决定切换主题。另:本文在调整的相对安逸之前会持续更新。

这个目标主题Maupassant,也是早就看上的,但是考虑到next实在太方便了才没能有勇气换过去。直到最近假期才敢小小的折腾一下。在这里感谢一下将这个主题移植到hexo博客系统的大大。如果有机会的话我要尝试把它移植到HUGO上看看。稍微小小的看了一下,虽然用的人很多。但是因为结构不算复杂,而且pug格式也方便和纯HTML进行转换,因此可以随时随地添加自己喜欢的插件,把博客改造成自己中意的样子。接下来尽可能简单的并详细的介绍下改造以及部署流程。

主体部分

hexo部署

这个我想既然会看这篇文章的话至少说明回去读hexo的文档吧!但是以防万一还是从基础开始。

首先配置好nodejs环境,这个绝对不会再写了,无论是哪个平台教程都多得很。

1
$ yarn add hexo-cli

这样就部署完成了hexo本体。像我一样做过系统迁移的人,可能需要直接在博客工程文件文件夹内执行:

1
$ npm install

然后参考文档建立初始站点,此时应该是使用了landscape主题。那么接下来填写好hexo的_config.yml相关内容。这部分的各个参数请直接参考hexo官方介绍。因为几乎都是自然语言,因此并不难处理。

Maupassant主题部署

和大多数hexo引擎的主题采用swig格式的模版不同,Maupassant使用的是pug格式的模版,这个之前也说过了。这种格式并没有比起原生HTML来的更有什么优势。但是可以单独罗列各个部分组件可以更方便的互相拼凑。

按照README,执行一下命令进行部署(我权当此时你仍在工程文件的根目录下):

1
2
3
$ git clone https://github.com/tufu9441/maupassant-hexo.git themes/maupassant
$ yarn add hexo-renderer-pug
$ yarn add hexo-renderer-sass

此时hexo应该有能力渲染pug模版的页面了。

接下来仍然是根据自己需求修改_config.yml文件。这部分也没什么好说的。

开始魔改

为什么说是魔改,因为都是只涉及到前端所需要的代码,相对容易修改和调试,只要稍花点心思就可以调整成自己想要的样子。

修改永久链接&添加评论

首先是修改评论系统。之前已知使用Disqus!作为评论系统的,但是由于众所周知的原因,这货并没想象的那么棒,那么需要一个相对折中的方案。最开始想选择更为流行的Gitment,但是作者服务器到期了,因此更换为GitTalk。如果只是简单的添加评论系统的话并不能称得上是魔改。如果各位仔细观察的话会发现hexo的文章链接形式都是时间+文章名,这样就难免出现比如中文标题的文章不能初始化评论的问题。

因此这时候需要用到这款插件:hexo-abbrlink。主要作用是将原本非常长的文章链接修改成比较短的、数字加字母的随机生成的链接。

执行:

1
$ yarn add hexo-abbrlink

添加该插件。然后修改站点的_config.yml:

添加内容:

1
2
3
4
#abbrlink
abbrink:
alg: crc32
rep: dec

并修改永久链接样式:

1
permalink: posts/:abbrlink.html

这时候重新生成饮下会发现所有文章链接变成了相对短的链接。而且这款插件会在生成新post时候自动添加选项。非常方便。如果不放心的话可以修改post模版文件。

修改文章文件名

为什么要单列出来这个,因为我们有了addrlink这个好东西。但是无论是用什么来管理文章的话,如果全部是带有下划线或者短杠的文件名的话并不利于管理。因此修改站点配置文件_config.yml:

1
new_post_name: :year-:month-:day-:title.md # File name of new posts

添加进度条效果

这个其实应该是不算难的。因为只涉及到修改CSS部分以及引入pace.js。

注:以下全部都涉及到主题模版的修改,请全部在主题文件夹进行

修改head.pug:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 //- 插入进度条
script(src='//cdn.bootcss.com/pace/1.0.2/pace.min.js')
link(href='//cdn.bootcss.com/pace/1.0.2/themes/pink/pace-theme-flash.css', rel='stylesheet')
style.
.pace .pace-progress {
background: #1abc9c;
height: 3px;
}
.pace .pace-progress-inner {
box-shadow: 0 0 10px #1abc9c, 0 0 5px #1abc9c;
}
.pace .pace-activity {
border-top-color: #1abc9c;
border-left-color: #1abc9c;
}
//- 插入进度掉end

如果实在是无法手写pug的话可以先考虑写成HTML再用转换工具进行转换。

添加点击的烟花效果

同样修改head.pug,添加如下行:

1
2
3
4
5
6
//- 烟花点击效果
if theme.fireworks
canvas.fireworks(style='position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;')
script(type='text/javascript', src='//cdn.bootcss.com/animejs/2.2.0/anime.min.js')
script(type='text/javascript', src='/js/fireworks.js')
//- 烟花点击效果end

在source/js/下添加fireworks.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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"use strict";

function updateCoords(e) {
pointerX = (e.clientX || e.touches[0].clientX) - canvasEl.getBoundingClientRect().left, pointerY = e.clientY || e.touches[0].clientY - canvasEl.getBoundingClientRect().top
}

function setParticuleDirection(e) { var t = anime.random(0, 360) * Math.PI / 180,
a = anime.random(50, 180),
n = [-1, 1][anime.random(0, 1)] * a; return { x: e.x + n * Math.cos(t), y: e.y + n * Math.sin(t) } }

function createParticule(e, t) { var a = {}; return a.x = e, a.y = t, a.color = colors[anime.random(0, colors.length - 1)], a.radius = anime.random(16, 32), a.endPos = setParticuleDirection(a), a.draw = function() { ctx.beginPath(), ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0), ctx.fillStyle = a.color, ctx.fill() }, a }

function createCircle(e, t) { var a = {}; return a.x = e, a.y = t, a.color = "#F00", a.radius = 0.1, a.alpha = 0.5, a.lineWidth = 6, a.draw = function() { ctx.globalAlpha = a.alpha, ctx.beginPath(), ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0), ctx.lineWidth = a.lineWidth, ctx.strokeStyle = a.color, ctx.stroke(), ctx.globalAlpha = 1 }, a }

function renderParticule(e) { for (var t = 0; t < e.animatables.length; t++) { e.animatables[t].target.draw() } }

function animateParticules(e, t) { for (var a = createCircle(e, t), n = [], i = 0; i < numberOfParticules; i++) { n.push(createParticule(e, t)) }
anime.timeline().add({ targets: n, x: function(e) { return e.endPos.x }, y: function(e) { return e.endPos.y }, radius: 0.1, duration: anime.random(1200, 1800), easing: "easeOutExpo", update: renderParticule }).add({ targets: a, radius: anime.random(80, 160), lineWidth: 0, alpha: { value: 0, easing: "linear", duration: anime.random(600, 800) }, duration: anime.random(1200, 1800), easing: "easeOutExpo", update: renderParticule, offset: 0 }) }

function debounce(e, t) { var a; return function() { var n = this,
i = arguments;
clearTimeout(a), a = setTimeout(function() { e.apply(n, i) }, t) } }
var canvasEl = document.querySelector(".fireworks");
if (canvasEl) { var ctx = canvasEl.getContext("2d"),
numberOfParticules = 30,
pointerX = 0,
pointerY = 0,
tap = "mousedown",
colors = ["#FF1461", "#18FF92", "#5A87FF", "#FBF38C"],
setCanvasSize = debounce(function() { canvasEl.width = 2 * window.innerWidth, canvasEl.height = 2 * window.innerHeight, canvasEl.style.width = window.innerWidth + "px", canvasEl.style.height = window.innerHeight + "px", canvasEl.getContext("2d").scale(2, 2) }, 500),
render = anime({ duration: 1 / 0, update: function() { ctx.clearRect(0, 0, canvasEl.width, canvasEl.height) } });
document.addEventListener(tap, function(e) { "sidebar" !== e.target.id && "toggle-sidebar" !== e.target.id && "A" !== e.target.nodeName && "IMG" !== e.target.nodeName && (render.play(), updateCoords(e), animateParticules(pointerX, pointerY)) }, !1), setCanvasSize(), window.addEventListener("resize", setCanvasSize, !1) }
"use strict";

function updateCoords(e) { pointerX = (e.clientX || e.touches[0].clientX) - canvasEl.getBoundingClientRect().left, pointerY = e.clientY || e.touches[0].clientY - canvasEl.getBoundingClientRect().top }

function setParticuleDirection(e) { var t = anime.random(0, 360) * Math.PI / 180,
a = anime.random(50, 180),
n = [-1, 1][anime.random(0, 1)] * a; return { x: e.x + n * Math.cos(t), y: e.y + n * Math.sin(t) } }

function createParticule(e, t) { var a = {}; return a.x = e, a.y = t, a.color = colors[anime.random(0, colors.length - 1)], a.radius = anime.random(16, 32), a.endPos = setParticuleDirection(a), a.draw = function() { ctx.beginPath(), ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0), ctx.fillStyle = a.color, ctx.fill() }, a }

function createCircle(e, t) { var a = {}; return a.x = e, a.y = t, a.color = "#F00", a.radius = 0.1, a.alpha = 0.5, a.lineWidth = 6, a.draw = function() { ctx.globalAlpha = a.alpha, ctx.beginPath(), ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0), ctx.lineWidth = a.lineWidth, ctx.strokeStyle = a.color, ctx.stroke(), ctx.globalAlpha = 1 }, a }

function renderParticule(e) { for (var t = 0; t < e.animatables.length; t++) { e.animatables[t].target.draw() } }

function animateParticules(e, t) { for (var a = createCircle(e, t), n = [], i = 0; i < numberOfParticules; i++) { n.push(createParticule(e, t)) }
anime.timeline().add({ targets: n, x: function(e) { return e.endPos.x }, y: function(e) { return e.endPos.y }, radius: 0.1, duration: anime.random(1200, 1800), easing: "easeOutExpo", update: renderParticule }).add({ targets: a, radius: anime.random(80, 160), lineWidth: 0, alpha: { value: 0, easing: "linear", duration: anime.random(600, 800) }, duration: anime.random(1200, 1800), easing: "easeOutExpo", update: renderParticule, offset: 0 }) }

function debounce(e, t) { var a; return function() { var n = this,
i = arguments;
clearTimeout(a), a = setTimeout(function() { e.apply(n, i) }, t) } }
var canvasEl = document.querySelector(".fireworks");
if (canvasEl) {
var ctx = canvasEl.getContext("2d"),
numberOfParticules = 30,
pointerX = 0,
pointerY = 0,
tap = "mousedown",
colors = ["#FF1461", "#18FF92", "#5A87FF", "#FBF38C"],
setCanvasSize = debounce(function() { canvasEl.width = 2 * window.innerWidth, canvasEl.height = 2 * window.innerHeight, canvasEl.style.width = window.innerWidth + "px", canvasEl.style.height = window.innerHeight + "px", canvasEl.getContext("2d").scale(2, 2) }, 500),
render = anime({ duration: 1 / 0, update: function() { ctx.clearRect(0, 0, canvasEl.width, canvasEl.height) } });
document.addEventListener(tap, function(e) { "sidebar" !== e.target.id && "toggle-sidebar" !== e.target.id && "A" !== e.target.nodeName && "IMG" !== e.target.nodeName && (render.play(), updateCoords(e), animateParticules(pointerX, pointerY)) }, !1), setCanvasSize(), window.addEventListener("resize", setCanvasSize, !1)
};

这个部分可以自己按照洗好做一定的修改,会有不一样的效果。

添加不蒜子站点浏览数

修改footer.pug,并添加如下行:

1
2
3
4
5
6
7
8
9
10
11
script(async='', src='https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js')
span#busuanzi_container_site_pv
i.fa.fa-eye
| 访问量
span#busuanzi_value_site_pv
| 次 |
span#busuanzi_container_site_uv
i.fa.fa-user-md
| 访客数
span#busuanzi_value_site_uv
| 人
1
hello world

由于pug对空格敏感,因此空格多少可以相对容易的调整。

添加clipboard.js

(待完成)