Klapring

Fluid 主题无侵入改造记录

更新日志

警告本博客已更换至 Solitude 主题,Fluid 主题相关内容仅供参考。

本博客已更换至 Astral Halo 主题,Solitude 与 Fluid 主题相关内容仅供参考。

本博客已更换至 Kerplunk 主题,Astral Halo、Solitude 与 Fluid 主题相关内容仅供参考。

HexoFluid 主题是一个很好的主题,功能基本完整,页面简洁,加载浏览都很流畅。但是我对这个主题的页面仍有想修改的地方,特此记录。

同时为了保证在更新主题是不会影响我的修改,因此本文中所有修改都是非侵入式(不修改主题源代码)的。

文章时效性提示

source/custom/js 目录下新建 outdate-notice.js 文件:

// source/custom/js/outdate-notice.js
window.onload = function () {
//不同的日期显示不同的样式,200 天为黄色提示,400天为红色提示,可以自己定义。
let warningDay = 200;
let errorDay = 600;
// 确保能够获取到文章时间以及在文章详情页
let times = document.getElementsByTagName('time');
if (times.length === 0) {
return;
}
let posts = document.getElementsByClassName('post-content');
if (posts.length === 0) {
return;
}
// 获取系统当前的时间
let pubTime = new Date(times[0].dateTime); /* 文章发布时间戳 */
let now = Date.now(); /* 当前时间戳 */
let interval = parseInt(now - pubTime);
let days = parseInt(interval / 86400000);
/* 发布时间超过指定时间(毫秒) */
//note warning 以及 note danger 是 Next 主题的自定义模板语法,如果使用其他主题,请自行更改样式以达到最佳显示效果
if (interval > warningDay * 3600 * 24 * 1000 && interval < errorDay * 3600 * 24 * 1000) {
posts[0].innerHTML =
'<div class="note note-warning">' +
'<h5>文章时效性提示</h5><p>这是一篇发布于 ' +
days +
' 天前的文章,部分信息可能已发生改变,请注意甄别。</p>' +
'</div>' +
posts[0].innerHTML;
} else if (interval >= errorDay * 3600 * 24 * 1000) {
posts[0].innerHTML =
'<div class="note note-danger">' +
'<h5>文章时效性提示</h5><p>这是一篇发布于 ' +
days +
' 天前的文章,部分信息可能已发生改变,请注意甄别。</p>' +
'</div>' +
posts[0].innerHTML;
}
};

在之前创建的 scripts/injector.js 中新增:

// scripts/injector.js
// 注入文章时效性提示
hexo.extend.injector.register(
'body_end',
`<script src="custom/js/outdate-notice.js"></script>`,
'post'
);

使用 hexo cl + hexo d -g 重新生成并部署即可。

代码块美化

scripts 目录下新建 code-pretty.js 文件:

// scripts/code-pretty.js
'use strict';
// 获取唯一 ID
function getUuid() {
return Math.random().toString(36).substring(2, 8) + Date.now().toString(36);
}
hexo.extend.filter.register(
'after_post_render',
(data) => {
const { line_number, lib } = hexo.theme.config.code.highlight;
let reg;
if (lib === 'highlightjs') {
if (line_number) {
reg = /(<figure class="highlight.+?>)(.+?hljs (.*?)".+?)(<\/figure>)/gims;
} else {
reg = /(<div class="code-wrapper.+?>)(.+?hljs (.*?)".+?)(<\/div>)/gims;
}
} else if (lib === 'prismjs') {
reg = /(<div class="code-wrapper.+?>)(.+?data-language="(.*?)".+?)(<\/div>)/gims;
}
data.content = data.content.replace(
reg,
(match, begin, inner, lang, end, offset, string) => {
const collapseId = `collapse-${getUuid()}`;
const collapseBtn = `<i class="iconfont icon-code" type="button" data-toggle="collapse" data-target="#${collapseId}"></i>`;
const collapseDiv = `<div class="collapse show" id="${collapseId}">${inner}</div>`;
const langSpan = `<span>${lang.toUpperCase()}</span>`;
return begin + collapseBtn + langSpan + collapseDiv + end;
}
);
return data;
},
10000 // 应该在完成其他渲染后执行,因此将优先级设大一点
);
提示:如果需要修改代码块右上角图标,请更换 collapseBtn 的 icon 部分 "iconfont icon-code"

再在 custom/css 中新建 code-pretty.styl 文件

// custom/css/code-pretty.styl
.markdown-body .highlight table,
.markdown-body .code-wrapper pre {
border-radius: 0 0 0.5rem 0.5rem;
}
.markdown-body .highlight,
.markdown-body .code-wrapper {
background-color: #e6ebf1;
border-radius: 0.625rem;
// 折叠图标
> i {
color: #777777;
margin-left: 10px;
line-height: 2rem;
transform: none;
transition: color 0.2s ease-in-out, transform 0.2s ease-in-out;
// &.collapsed {
// transform: rotate(-90deg);
// }
}
// 代码语言
> span {
color: #777777;
margin-left: 10px;
font-weight: bold;
}
}
.copy-btn {
font-size: 1rem;
color: darkslategrey;
> i {
font-size: 1rem !important;
font-weight: bold;
}
}
[data-user-color-scheme='dark'] {
.copy-btn {
color: #c4c6c9;
transition: color 0.2s ease-in-out;
}
}
[data-user-color-scheme='dark'] {
.markdown-body .highlight,
.markdown-body .code-wrapper {
background-color: #696969;
transition: background-color 0.2s ease-in-out;
> i {
color: #c4c6c9;
}
> span {
color: #c4c6c9;
transition: color 0.2s ease-in-out;
}
}
}

_config.fluid.yml 中的 custom_css 配置项中添加:

# _config.fluid.yml
custom_css:
- custom/css/code-pretty

使用 hexo cl + hexo d -g 重新生成并部署即可。

浏览器恶搞标签

source 目录下新建 custom/js 目录,再在其中新建 label-page.js 文件,内容为:

// custom/js/label-page.js
// 浏览器搞笑标题
var OriginTitle = document.title;
var titleTime;
document.addEventListener('visibilitychange', function () {
if (document.hidden) {
document.title = '(´;ω;`) 你不要我了吗 - ' + OriginTitle;
clearTimeout(titleTime);
} else {
document.title = OriginTitle;
titleTime = setTimeout(function () {
document.title = OriginTitle;
}, 2000);
}
});

随后在 _config.fluid.yml 中的 custom_js 配置项中添加:

# _config.fluid.yml
custom_js:
- /custom/js/label-page.js # 浏览器恶搞标题

使用 hexo cl + hexo d -g 重新生成并部署即可。

背景动态线条

简单版

添加背景动态线条只需要在 _config.fluid.yml 中新增 custom_html 配置项并添加如下内容:

# _config.fluid.yml
custom_html:
- <script type="text/javascript" color="255,255,255" opacity="1.0" zIndex="-1" count="110" src="https://cdn.jsdelivr.net/npm/canvas-nest.js@1.0.1/dist/canvas-nest.js"></script>

使用 hexo cl + hexo d -g 重新生成并部署即可。

修改版

由于 canvas-nest.js2.0.0 以后所有版本都与 Fluid 主题有冲突,而 1.0.1 版本不能修改点的颜色,只能修改线条颜色,因此还可以选择将 1.0.1 版本的 js 文件下载到本地进行修改。

下载源文件到本地 source/custom/js 目录下,分别修改以下内容:

// source/custom/js/canvas-nest.js
p: get_attribute(script, "pointColor", "0,0,0"), //pointColor
// source/custom/js/canvas-nest.js
context.fillStyle = "rgba(" + config.p + ")",

然后在 _config.fluid.yml 中新增 custom_html 配置项并添加如下内容:

# _config.fluid.yml
custom_html:
- <script type="text/javascript" color="255,255,255" pointColor="252,228,236" opacity="1.0" zIndex="-1" count="110" src="/custom/js/canvas-nest.js"></script>

使用 hexo cl + hexo d -g 重新生成并部署即可。

顶部阅读进度条

source/custom/js 目录下新建 read-progress-bar.js 文件:

// source/custom/js/read-progress-bar.js
document.addEventListener('DOMContentLoaded', function () {
var winHeight = window.innerHeight,
docHeight = document.documentElement.scrollHeight,
progressBar = document.querySelector('#content_progress');
progressBar.max = docHeight - winHeight;
progressBar.value = window.scrollY;
document.addEventListener('scroll', function () {
progressBar.max = document.documentElement.scrollHeight - window.innerHeight;
progressBar.value = window.scrollY;
});
});

再在 source/custom/css 目录下新建 read-progress-bar.css 文件:

/* source/custom/css/read-progress-bar.css */
#content_progress {
/* Positioning */
position: fixed;
left: 0;
top: 0;
z-index: 32766;
width: 100%;
height: 6px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
background-color: transparent;
color: #ffffff80; /* 使用半透明白色,适配夜间模式 */
}
#content_progress::-webkit-progress-bar {
background-color: transparent;
}
#content_progress::-webkit-progress-value {
background-color: #ffffff80;
}
#content_progress::-moz-progress-bar {
background-color: #ffffff80;
}

接着在 scripts 目录下新建 injector.js 文件:

// scripts/injector.js
// 注入阅读进度条
hexo.extend.injector.register(
'head_begin',
'<progress id="content_progress" value="0"></progress>',
'post'
);

最后在 _config.fluid.yml 中的 custom_jscustom_css 配置项中添加:

# _config.fluid.yml
custom_js:
- custom/js/read-progress-bar.js
custom_css:
- custom/css/read-progress-bar.css

使用 hexo cl + hexo d -g 重新生成并部署即可。

建站时间

source/custom/js 目录下新建 create-time.js 文件:

// source/custom/js/create-time.js
var now = new Date();
function createtime() {
var grt = new Date('08/19/2024 12:00: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);

_config.fluid.yml 中的 custom_js 配置项中添加:

# _config.fluid.yml
custom_js:
- custom/js/create-time.js

最后在 _config.fluid.yml 中修改 footer/content 配置项,新增一行

<br /><span id="timeDate">天数载入中</span><span id="times">...</span><br />

即将 footer/content 配置项修改为如下形式:

# _config.fluid.yml
footer:
content: '
<a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a>
<i class="iconfont icon-love"></i>
<a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a>
<br><span id="timeDate">天数载入中</span><span id="times">...</span><br>
'

使用 hexo cl + hexo d -g 重新生成并部署即可。

随机文章跳转

该方法需要先生成 sitemap,可以参考我的另一篇文章

先在 source/custom/js 目录下新建 random-post.js 文件:

// source/custom/js/random-post.js
function randomPost() {
fetch('/sitemap.xml')
.then((res) => res.text())
.then((str) => new window.DOMParser().parseFromString(str, 'text/xml'))
.then((data) => {
let ls = data.querySelectorAll('url loc');
let locationHref, locSplit;
do {
locationHref = ls[Math.floor(Math.random() * ls.length)].innerHTML;
locSplit = locationHref.split('/')[3] || '';
// } while (locSplit == '' || locSplit == 'tags');
//若所有文章都如 https://…….com/posts/2022/07/…… 格式,主域名后字符是 posts,则循环条件改为:
} while (locSplit !== 'posts');
location.href = locationHref;
});
}

_config.fluid.yml 中的 custom_js 配置项中添加:

# _config.fluid.yml
custom_js:
- custom/js/random-post.js

随后在喜欢的位置放上 javascript:randomPost(); 的跳转链接,例如在导航栏:

# _config.fluid.yml
menu:
- {
key: 'random',
name: '随机文章',
link: 'javascript:randomPost();',
icon: 'iconfont icon-random',
}

使用 hexo cl + hexo d -g 重新生成并部署即可。

提示:以上代码中 icon: "iconfont icon-random" 使用了我自己的 Iconfont图标库而非主题内置 Iconfont 图标库,有需要请自行到 Iconfont 创建自己的图标库。

新增标签语法

参看另一篇文章

参考资料

本篇文章内容参考了类似的大量文章内容,特此感谢(排名不分先后)