Fluid 主题魔改汇总

最后更新时间:2022-06-13



前言

所谓魔改,就是与主题不同,一旦主题已经被采用或者被实现,则会被划掉,而且魔改初心是使用无侵入式的方式修改——即不修改源码,而是使用注入器的方式。这样的话主题升级比较容易!

背景图片固定

需要使用注入器,如果没有injector.js文件,需要在博客根目录下创建scripts文件夹并新建injector.js文件,然后在你新建的文件中复制以下代码。

1
2
3
4
5
6
7
8
9
// 全屏背景的需要导入这些js
const { root: siteRoot = "/" } = hexo.config;
hexo.extend.injector.register("body_begin", `<div id="web_bg"></div>`);
hexo.extend.injector.register(
"body_end",
`<script src="${siteRoot}js/background.js"></script>
<link defer rel="stylesheet" href="${siteRoot}styles/background.css" />
`
);

js文件夹中新建background.js文件,内容如下:

1
2
3
4
5
6
7
8
9
const bannerContainer = $("#banner");
const viewBg = $("#web_bg");
const bannerMask = $("#banner .mask");
const bg = $(bannerContainer).css("background-image");
$(viewBg).css("background-image", bg);
$(bannerContainer).css("background-image", "url()");
const color = $(bannerMask).css("background-color");
$(bannerMask).css("background-color", `rgba(0,0,0,0)`);
$(viewBg).css("background-color", color);

css文件夹中新增background.css文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
#web_bg {
position: fixed;
z-index: -999;
width: 100%;
height: 100%;
background-attachment: local;
background-position: center;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
background-repeat: repeat;
}

日夜切换动画

onclick="switchNightMode()"添加到~/fluid/layout/_partials/header/navigation.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
32
33
function checkNightMode() {
'1' === localStorage.getItem('isDark') ? ($('body').addClass('DarkMode'), $('#changeMode-top').removeClass('fa-moon').addClass('fa-sun'), $('#modeicon').attr('xlink:href', '#icon-sun')) : '0' === localStorage.getItem('isDark') ? $('#modeicon').attr('xlink:href', '#icon-moon') : new Date().getHours() >= 20 || new Date().getHours() < 7 ? ($('body').addClass('DarkMode'), $('#changeMode-top').removeClass('fa-moon').addClass('fa-sun'), $('#modeicon').attr('xlink:href', '#icon-sun')) : matchMedia('(prefers-color-scheme: dark)').matches ? ($('body').addClass('DarkMode'), $('#changeMode-top').removeClass('fa-moon').addClass('fa-sun'), $('#modeicon').attr('xlink:href', '#icon-sun')) : $('#modeicon').attr('xlink:href', '#icon-moon')
}
function switchNightMode() {
$('<div class="Cuteen_DarkSky"><div class="Cuteen_DarkPlanet"></div></div>').appendTo($('body')),
setTimeout(function () {
$('body').hasClass('DarkMode') ? ($('body').removeClass('DarkMode'), localStorage.setItem('isDark', '0'), $('#changeMode-top').removeClass('fa-sun').addClass('fa-moon'), $('#modeicon').attr('xlink:href', '#icon-moon')) : ($('body').addClass('DarkMode'), localStorage.setItem('isDark', '1'), $('#changeMode-top').removeClass('fa-moon').addClass('fa-sun'), $('#modeicon').attr('xlink:href', '#icon-sun')),
setTimeout(function () {
$('.Cuteen_DarkSky').fadeOut(1e3, function () {
$(this).remove()
})
}, 2e3)
})
const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
if (nowMode === 'light') {
activateDarkMode()
saveToLocal.set('theme', 'dark', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
$('#modeicon').attr('xlink:href', '#icon-moon')
} else {
activateLightMode()
saveToLocal.set('theme', 'light', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
$('body').addClass('DarkMode'), $('#changeMode-top').removeClass('fa-moon').addClass('fa-sun'), $('#modeicon').attr('xlink:href', '#icon-sun')
}
// handle some cases
typeof utterancesTheme === 'function' && utterancesTheme()
typeof FB === 'object' && window.loadFBComment()
window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
}
function switchNightModeTop() {
$('body').hasClass('DarkMode') ? ($('body').removeClass('DarkMode'), localStorage.setItem('isDark', '0'), $('#changeMode-top').removeClass('fa-sun').addClass('fa-moon'), $('#modeicon').attr('xlink:href', '#icon-moon')) : ($('body').addClass('DarkMode'), localStorage.setItem('isDark', '1'), $('#changeMode-top').removeClass('fa-moon').addClass('fa-sun'), $('#modeicon').attr('xlink:href', '#icon-sun'))
}
查看代码
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
.Cuteen_DarkSky,
.Cuteen_DarkSky:before {
content: '';
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 88888888;
}
.Cuteen_DarkSky {
background: linear-gradient(#feb8b0, #fef9db);
}
.Cuteen_DarkSky:before {
transition: 2s ease all;
opacity: 0;
background: linear-gradient(#4c3f6d, #6c62bb, #93b1ed);
}
.DarkMode .Cuteen_DarkSky:before {
opacity: 1;
}
.Cuteen_DarkPlanet {
z-index: 99999999;
position: fixed;
left: -50%;
top: -50%;
width: 200%;
height: 200%;
-webkit-animation: CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1);
animation: CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1);
transform-origin: center bottom;
}
@-webkit-keyframes CuteenPlanetMove {
0% {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
@keyframes CuteenPlanetMove {
0% {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
.Cuteen_DarkPlanet:after {
position: absolute;
left: 35%;
top: 40%;
width: 9.375rem;
height: 9.375rem;
border-radius: 50%;
content: '';
background: linear-gradient(#fefefe, #fffbe8);
}
.search span{
display: none;
}
.menus_item a{
text-decoration: none!important;
}
/*深色模式按钮*/
.icon-V {
border-radius: 6px !important;
width: 18px;
height: 18px;
border-radius: 6px;
overflow: hidden;
position: relative;
top: 2rem;
left: 8rem;
transition: 1.3s cubic-bezier(0.53, 0, 0.15, 1.3);
z-index: 9999;
}

.icon-V svg{
width: 22px;
height: 22px;
position: absolute;
bottom: 0px;
margin: auto;
right: 1px;
}

随机文章

博客根目录/scripts(没有请自行创建)下新建random.js文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
hexo.extend.generator.register('random', function (locals) {
const config = hexo.config.random || {}
const posts = []
for (const post of locals.posts.data) {
if (post.random !== false) posts.push(post.path)
}
return {
path: config.path || 'random/index.html',
data: `<html><head><script>var posts=${JSON.stringify(posts)};window.open('/'+posts[Math.floor(Math.random() * posts.length)],"_self")</script></head></html>`
}
})

打开/random/就会随机跳转一篇文章,你还可以在_config.yml中添加以下配置:

1
2
random:
path: # 随机链接路径,默认"random/index.html"

如果不想随机跳转到某篇文章,只需在这篇文章Front-matter中添加random: false

赞赏按钮

创建一个 JavaScript 文件:/source/js/reward-button.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
65
function RewardButton(config) {
this.btnIcon = config.btnIcon;
this.btnText = config.btnText;
this.comment = config.comment;
this.qrcodes = config.qrcodes;
}

RewardButton.prototype = {
init: function () {
let btnId = "reward-btn";
let qrcodesId = "reward-qrcodes";

var btn = document.createElement("a");
btn.className = "btn";
btn.id = btnId;

if (this.btnIcon) {
btn.className = `${this.btnIcon} ${btn.className}`;
btn.innerHTML = " " + this.btnText;
} else {
btn.innerHTML = this.btnText;
}

var qrcodes = document.createElement("div");
qrcodes.id = qrcodesId;

var div = document.createElement("div");
div.className = "markdown-body";
div.style.textAlign = "center"
div.appendChild(btn);
div.innerHTML += `<br><span class="image-caption">${this.comment}</span>`;
div.appendChild(qrcodes);

var postNav = document.querySelector('.post-prevnext');
postNav.parentNode.insertBefore(div, postNav);

document.getElementById(btnId).onclick = (function () {
var container = document.getElementById(qrcodesId);

if (container.childNodes.length == 0) {
for (var i = 0; i < this.qrcodes.length; i++) {
var qrcode = document.createElement("p");
qrcode.className = "reward-qrcode";

var img = document.createElement("img");
img.src = this.qrcodes[i].src;
img.title = this.qrcodes[i].title;
img.alt = this.qrcodes[i].title;

var caption = document.createElement("p");
caption.className = "image-caption";
caption.innerText = this.qrcodes[i].caption;

qrcode.appendChild(img);
qrcode.appendChild(caption);
container.appendChild(qrcode);
}
} else if (container.style.display == "none") {
container.style.removeProperty("display");
} else {
container.style.display = "none";
}
}).bind(this);
}
};

创建一个 CSS 文件:/source/css/reward-button.css

查看代码
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#reward-btn {
border-radius: 20px;
margin-bottom: 0.625rem;
}

.reward-qrcode {
display: inline-block;
margin: 1.5rem !important;
width: 10rem;
height: 10rem;
-webkit-animation: show_qrcodes .3s .1s ease both;
-moz-animation: show_qrcodes .3s .1s ease both;
-o-animation: show_qrcodes .3s .1s ease both;
-ms-animation: show_qrcodes .3s .1s ease both;
animation: show_qrcodes .3s .1s ease both;
}

.reward-qrcode img {
margin-top: 0 !important;
}

@-moz-keyframes show_qrcodes {
0% {
opacity: 0;
-webkit-transform: translateY(-10px);
-moz-transform: translateY(-10px);
-o-transform: translateY(-10px);
-ms-transform: translateY(-10px);
transform: translateY(-10px);
}

100% {
opacity: 1;
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-o-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}

@-webkit-keyframes show_qrcodes {
0% {
opacity: 0;
-webkit-transform: translateY(-10px);
-moz-transform: translateY(-10px);
-o-transform: translateY(-10px);
-ms-transform: translateY(-10px);
transform: translateY(-10px);
}

100% {
opacity: 1;
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-o-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}

@-o-keyframes show_qrcodes {
0% {
opacity: 0;
-webkit-transform: translateY(-10px);
-moz-transform: translateY(-10px);
-o-transform: translateY(-10px);
-ms-transform: translateY(-10px);
transform: translateY(-10px);
}

100% {
opacity: 1;
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-o-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}

@keyframes show_qrcodes {
0% {
opacity: 0;
-webkit-transform: translateY(-10px);
-moz-transform: translateY(-10px);
-o-transform: translateY(-10px);
-ms-transform: translateY(-10px);
transform: translateY(-10px);
}

100% {
opacity: 1;
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-o-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}

编写注入器:/scripts/reward-button-injector.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
hexo.extend.injector.register('body_end', function () {
const {
enable,
btn_icon,
btn_text,
comment,
qrcodes,
} = hexo.config.reward_button;

if (!enable) {
return null;
}

return `
<link defer rel="stylesheet" href="/css/reward-button.css"/>
<script src="/js/reward-button.js"></script>
<script>
new RewardButton({
btnIcon: ${btn_icon ? `"${btn_icon}"` : "null"},
btnText: "${btn_text}",
comment: "${comment}",
qrcodes: ${JSON.stringify(qrcodes)}
}).init();
</script>
`
}, "post");

最后在博客根目录_config.yml中添加配置。

1
2
3
4
5
6
7
8
9
reward_button:
enable: true
btn_icon: iconfont icon-love
btn_text: 赞赏
comment: 我很可爱,请给我钱!
qrcodes:
- src: /img/赞赏码.jpg
caption: 微信
title: 微信赞赏码

迷你版权

创建一个 JavaScript 文件:/source/js/mini-copyright.js,然后粘贴下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function MiniCopyright(content) {
this.content = content;
}

MiniCopyright.prototype = {
init: function () {
var copyright = document.createElement("span");
copyright.innerHTML = this.content;

var div = document.createElement("div");
div.className = "markdown-body mini-copyright";
div.appendChild(copyright);

var hr = document.querySelector(".post-metas.mb-3").parentNode.previousElementSibling;
hr.parentNode.insertBefore(div, hr);
}
};

创建一个 CSS 文件:/source/css/mini-copyright.css

1
2
3
4
5
6
7
8
.mini-copyright {
margin-bottom: 0 !important;
}

.mini-copyright span {
opacity: 0.75;
font-size: 0.8rem;
}

编写注入器:/scripts/mini-copyright-injector.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
hexo.extend.injector.register('body_end', function () {
const {
enable,
content
} = hexo.config.mini_copyright;

if (!enable) {
return null;
}

return `
<link defer rel="stylesheet" href="/css/mini-copyright.css"/>
<script src="/js/mini-copyright.js"></script>
<script>
new MiniCopyright(\`${content}\`).init();
</script>
`
}, "post");

最后在博客根目录_config.yml中添加配置。

1
2
3
mini_copyright:
enable: true
content: '本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener">CC BY-SA 4.0 协议</a> ,转载请注明出处!'

总结

本篇文章用到了大量的 Hexo注入器,注入器被用于将静态代码片段注入生成的 HTML 的 <head> 和 <body> 中。更多注入器功能请参考:通过 Hexo 5 注入器为主题添加新功能



---------- 本文结束 感谢阅读 ----------

版权声明

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 协议 ,转载请注明出处!


Fluid 主题魔改汇总
https://blog.xukaiyyds.cn/posts/e10c888a/
作者
xukai
发布于
2022年4月21日
更新于
2022年6月13日
许可协议