博客哔哔更换记录

本文以《Hexo 博客哔哔更换记录》修改而成,代码根据我的需求进行一些微调,仅供学习参考。

部署

部署建议跟着官方文档就行,基本不会出什么问题。

这里给几点注意事项,我踩的坑:

  • 本项目两个仓库fork到自己仓库时,一定要把Copy the master branch only取消勾选(默认会勾选),将所有分支都fork到自己仓库。

    如图所示

  • 弄后台填写环境变量时直接复制粘贴,结果多了一个斜杠,后台会登陆不上,要注意一下
    例如让填:https://kkapi-open.vercel.app
    然后我填成了:https://kkapi-open.vercel.app/

  • 填写变量时,mongoDB的账号密码不需要填写
    mongodb的url里面已经有账号和密码了,所以变量只需要填url和那个加密的即可,加密的内容是随便填的。

然后根据文档完成相关的部署工作,最后进入后台,到这里后端就已经全部完成了。

前端

这里的前端部分我按照我之前的哔哔进行了一些修改,我的js和css仅适合我自己,你们可以去看一下原文,按照自己的需求来。

首页轮播

修改源码

为了方便,我们直接修改源码使固定页面引用css和js文件
修改butterfly\layout\index.pug

1
2
3
4
5
6
7
8
9
10
extends includes/layout.pug

block content
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts
+ #bber-talk
+ script(src='/static/timeago.min.js')
+ script(src='/static/bbtalk.js')
+postUI
include includes/pagination.pug

bbtalk.css

由于本站的CSS文件都做了整合,所以将bbtalk.css建在了\butterfly\source\css\_custom目录下,没整合css的也可以直接引入,跟正常魔改的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
101
102
103
104
105
106
107
108
/* 以下颜色设置 */
[data-theme=light] {
--sianx_bb_color:#edf4ff;
--sianx_text_color:#6667ab;
}

[data-theme=dark] {
--sianx_bb_color: #edf0f70d;
--sianx_text_color:#ffffffb3;
}
/* 首页轮播 */

#bber-talk,
#bber-talk a {
color: var(--font-color);
}

#bber-talk {
cursor: pointer;
width: 100%;
min-height: 50px;
background: var(--card-bg);
padding: 0.5rem 1rem;
border-radius: 14px;
display: flex;
align-items: center;
overflow: hidden;
/* font-weight: bold; */
height: 25px;

}

#bber-talk .item i {
margin-left: 5px;
}

#bber-talk>i {
font-size: 1.1rem;
}

#bber-talk .talk-list {
text-align: center;/* 文本居中 */
max-height: 32px;
font-size: 16px;
overflow: hidden;
padding-left: 0px;/* 去掉时间后的后遗症解决方案 */
}

#bber-talk .talk-list :hover {
color: #49b1f5 !important;
transition: all .2s ease-in-out;
}

#bber-talk .talk-list li {
list-style: none;
width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
margin-left: 0px;/* 去掉时间后的后遗症解决方案 */
}

#bber-talk .bber-icon {
line-height: 25px;
margin-left: 8px;
transition: 0.3s;
}

#bber-talk .pass {
-webkit-animation: 1s passing infinite;
animation: 1s passing infinite;
}

@-webkit-keyframes passing {
0% {
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
opacity: 0;
}
50% {
-webkit-transform: translateX(0);
transform: translateX(0);
opacity: 1;
}
100% {
-webkit-transform: translateX(50%);
transform: translateX(50%);
opacity: 0;
}
}

@keyframes passing {
0% {
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
opacity: 0;
}
50% {
-webkit-transform: translateX(0);
transform: translateX(0);
opacity: 1;
}
100% {
-webkit-transform: translateX(50%);
transform: translateX(50%);
opacity: 0;
}
}

bbtalk.js

source/static目录下创建bbtalk.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
let jsonUrl = 'https://kkapi-open-one.vercel.app/api/ispeak?author=个人id' // 在这修改api,改成自己的api地址https://kkapi.vercel.app/api/ispeak?author=个人id,这里的author为后台-个人设置里面的个人ID。

document.getElementById('bber-talk').addEventListener('click', () => {
window.location.pathname = '/time/' // 在这修改你的哔哔页面地址
})

bbtalk();

function bbtalk() {
let data = JSON.parse(localStorage.getItem('bibi'));
let nowTime = Date.now();
let ls;
if (data == null || nowTime - data.time >= 1800000) { // 设置缓存时长,单位毫秒,默认30分钟,建议10分钟以上,不能为0,想不缓存自己改代码。
getData();
return
} else {
ls = JSON.parse(data.ls)
};
let bberHtml = ''
ls.forEach((item, i) => {
let br = /[\s\uFEFF\xA0]+/g;
item.content = item.content.replace(br, '')
let d = new Date(item.createdAt)
let date = d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate() + ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds()
let dataTime = timeago.format(date, 'zh_CN');
let newdataTime = ''

bberHtml += '<li class="item item-' + (i + 1) + '">' + newdataTime + ' ' + urlToLink(item.content) + '</li>'
});
document.getElementById("bber-talk").innerHTML += '<i style="margin-right: 10px;" class="fa-regular fa-message"></i><ul class="talk-list">' + bberHtml + '</ul><i class="fa-solid fa-angles-right pass bber-icon"></i>'
}

function getData() {
fetch(jsonUrl)
.then(res => res.json())
.then((data) => {
data = { time: Date.now(), ls: JSON.stringify(data.data.items) }
localStorage.setItem('bibi', JSON.stringify(data))
}).then(() => {
bbtalk();
}).catch(() => {
console.log('获取哔哔数据失败!');
});
}

function urlToLink(str) {
let re_forimg = /<img(.*?)src=[\"|\']?(.*?)[\"|\']?(.*?)>|!\[(.*?)\]\((.*?)\)/g;
str = str.replace(re_forimg, '<i class="fa-solid fa-image"></i>');
return str
}

function Roll() {
try {
let list_li = Array.prototype.slice.call(document.querySelectorAll('.talk-list li'));
let tmp = list_li[0];
list_li.splice(0, 1);
list_li.push(tmp);
let list = document.querySelector('ul.talk-list')
list_li.forEach((item) => {
list.appendChild(item)
});
} catch (error) {}
};
setInterval(Roll, 3000);// 首页轮播时间

timeago.min.js

source/static目录下创建timeago.js,这个直接创建文件粘贴就行,是一个工具文件。

1
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).timeago={})}(this,function(e){"use strict";var r=["second","minute","hour","day","week","month","year"];var a=["秒","分钟","小时","天","周","个月","年"];function t(e,t){n[e]=t}function i(e){return n[e]||n.en_US}var n={},f=[60,60,24,7,365/7/12,12];function o(e){return e instanceof Date?e:!isNaN(e)||/^\d+$/.test(e)?new Date(parseInt(e)):(e=(e||"").trim().replace(/\.\d+/,"").replace(/-/,"/").replace(/-/,"/").replace(/(\d)T(\d)/,"$1 $2").replace(/Z/," UTC").replace(/([+-]\d\d):?(\d\d)/," $1$2"),new Date(e))}function d(e,t){for(var n=e<0?1:0,r=e=Math.abs(e),a=0;e>=f[a]&&a<f.length;a++)e/=f[a];return(0===(a*=2)?9:1)<(e=Math.floor(e))&&(a+=1),t(e,a,r)[n].replace("%s",e.toString())}function l(e,t){return((t?o(t):new Date)-o(e))/1e3}var s="timeago-id";function h(e){return parseInt(e.getAttribute(s))}var p={},v=function(e){clearTimeout(e),delete p[e]};function m(e,t,n,r){v(h(e));var a=r.relativeDate,i=r.minInterval,o=l(t,a);e.innerText=d(o,n);var u,c=setTimeout(function(){m(e,t,n,r)},Math.min(1e3*Math.max(function(e){for(var t=1,n=0,r=Math.abs(e);e>=f[n]&&n<f.length;n++)e/=f[n],t*=f[n];return r=(r%=t)?t-r:t,Math.ceil(r)}(o),i||1),2147483647));p[c]=0,u=c,e.setAttribute(s,u)}t("en_US",function(e,t){if(0===t)return["just now","right now"];var n=r[Math.floor(t/2)];return 1<e&&(n+="s"),[e+" "+n+" ago","in "+e+" "+n]}),t("zh_CN",function(e,t){if(0===t)return["刚刚","片刻后"];var n=a[~~(t/2)];return[e+" "+n+"前",e+" "+n+"后"]}),e.cancel=function(e){e?v(h(e)):Object.keys(p).forEach(v)},e.format=function(e,t,n){return d(l(e,n&&n.relativeDate),i(t))},e.register=t,e.render=function(e,t,n){var r=e.length?e:[e];return r.forEach(function(e){m(e,e.getAttribute("datetime"),i(t),n||{})}),r},Object.defineProperty(e,"__esModule",{value:!0})});

哔哔页面

新建哔哔页面

使用 hexo n page 'bb' 创建页面,然后引入js

1
2
3
4
5
6
7
8
9
10
11
12
---
title:
date: 2022-04-13 22:06:17
aside: false
comments: false
type: time
---
+ <script src="/static/bibi.js"></script>

+ <div id="bibi">
+ <div class="bb-info"></div><div id="bb-main"></div>
+ </div>

bbtalk.css

在刚才上面创建的bbtalk.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* 哔哔页面 */

#bibi button {
cursor: pointer;
color: #fff;
border: 0;
margin: 20px auto;
border-radius: 0.3125rem;
display: block;
padding: 0 1rem;
height: 40px;
font-weight: 500;
text-align: center;
transition: all 0.5s ease-out;
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 1000% 1000%;
animation: Gradient 60s linear infinite;
outline: 0;
}

#bibi .bb-info {
font-weight: 700;
font-size: 18px;
}

#bibi .bb-card {
padding: 10px 20px;
border-radius: 10px;
background: var(--sianx_bb_color);
overflow: hidden;
margin-top: 20px;
transition: all 0.25s;
user-select: none;
border: 2px solid var(--sianx_card-inner);
overflow: hidden;
}

#bibi .bb-card:hover {
transform: translateY(-3px);
/* border: 2px solid #9c9; */
overflow: hidden;
}

#bibi .card-header {
display: flex;
align-items: center;
}

#bibi .card-header .avatar {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 10px;
border-radius: 20px;
overflow: hidden;
}

#bibi .card-header svg {
height: 20px;
width: 20px;
margin-left: 5px;
}

#bibi .card-header .card-time {
font-size: 12px;
text-shadow: #d9d9d9 0 0 1px, #fffffb 0 0 1px, #fffffb 0 0 2px;
margin-left: 10px;
}

#bibi .card-content {
padding: 10px 0;
white-space: pre-wrap;
color: var(--sianx_text_color);
font-weight: 700;
}

#bibi .card-footer {
display: flex;
padding-bottom: 10px;
}

#bibi .card-footer .card-label {
border-radius: 5px;
padding: 0 5px;
font-weight: 550;
border-radius: 3px;
box-shadow: inset 0 -1px 0 rgb(27 31 35 / 12%);
font-size: 14px;
cursor: pointer;
user-select: none;
margin-right: 10px;
}

#article-container .card-content img {
margin: 0;
}

@media screen and (min-width: 768px) {
.card-content .fancybox,
.card-content video {
display: inline-block;
max-width: 40%;
margin-right: 10px;
}
}

@media screen and (max-width: 768px) {
.card-content .fancybox,
.card-content video {
display: inline-block;
max-width: 48%;
margin: 1%;
}
}

@keyframes Gradient {
0% {
background-position: 0 50%;
}
50% {
background-position: 100% 50%;
}
to {
background-position: 0 50%;
}
}
#bb-main{display:flex;flex-wrap:wrap;justify-content:space-between}
.bb-card{display:flex;flex-direction:column;position:relative;width:32%;margin:10px 0;box-sizing:border-box;padding:1rem}


@media screen and (max-width:1100px) {
.bb-card {
width:49%;
}
}
@media screen and (max-width:768px) {
.bb-card {
width:100%;
}
}

#loading {
display: flex;
justify-content: center;
align-items: center;
}

bibi.js

source/static目录下创建bibi.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
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
101
102
let svg = '<svg  viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" class="is-badge"><path  d="m512 268c0 17.9-4.3 34.5-12.9 49.7s-20.1 27.1-34.6 35.4c.4 2.7.6 6.9.6 12.6 0 27.1-9.1 50.1-27.1 69.1-18.1 19.1-39.9 28.6-65.4 28.6-11.4 0-22.3-2.1-32.6-6.3-8 16.4-19.5 29.6-34.6 39.7-15 10.2-31.5 15.2-49.4 15.2-18.3 0-34.9-4.9-49.7-14.9-14.9-9.9-26.3-23.2-34.3-40-10.3 4.2-21.1 6.3-32.6 6.3-25.5 0-47.4-9.5-65.7-28.6-18.3-19-27.4-42.1-27.4-69.1 0-3 .4-7.2 1.1-12.6-14.5-8.4-26-20.2-34.6-35.4-8.5-15.2-12.8-31.8-12.8-49.7 0-19 4.8-36.5 14.3-52.3s22.3-27.5 38.3-35.1c-4.2-11.4-6.3-22.9-6.3-34.3 0-27 9.1-50.1 27.4-69.1s40.2-28.6 65.7-28.6c11.4 0 22.3 2.1 32.6 6.3 8-16.4 19.5-29.6 34.6-39.7 15-10.1 31.5-15.2 49.4-15.2s34.4 5.1 49.4 15.1c15 10.1 26.6 23.3 34.6 39.7 10.3-4.2 21.1-6.3 32.6-6.3 25.5 0 47.3 9.5 65.4 28.6s27.1 42.1 27.1 69.1c0 12.6-1.9 24-5.7 34.3 16 7.6 28.8 19.3 38.3 35.1 9.5 15.9 14.3 33.4 14.3 52.4zm-266.9 77.1 105.7-158.3c2.7-4.2 3.5-8.8 2.6-13.7-1-4.9-3.5-8.8-7.7-11.4-4.2-2.7-8.8-3.6-13.7-2.9-5 .8-9 3.2-12 7.4l-93.1 140-42.9-42.8c-3.8-3.8-8.2-5.6-13.1-5.4-5 .2-9.3 2-13.1 5.4-3.4 3.4-5.1 7.7-5.1 12.9 0 5.1 1.7 9.4 5.1 12.9l58.9 58.9 2.9 2.3c3.4 2.3 6.9 3.4 10.3 3.4 6.7-.1 11.8-2.9 15.2-8.7z" fill="#1da1f2"></path></svg>'
let total = 0
let nowNum = 0
let items = []
let page = 1
let Url = 'https://kkapi.vercel.app/api/ispeak?author=个人id&page=' // 修改api,直接按照我给好的模板来,记得带参数page


window.addEventListener('DOMContentLoaded', () => {
getNew();
});
/*
// 获取数据
function getNew() {
let bibi = document.getElementById('bibi');
try {
bibi.removeChild(document.getElementById('more'))
} catch (error) {}

bibi.innerHTML += '<div id="loading">正在加载中...</div>' // 可以自己写加载中的显示内容,可用Html。

fetch(Url + page).then(res => res.json()).then((res) => {
total = res.data.total
items = res.data.items
nowNum += items.length
if (page == 1) {
document.querySelector('.bb-info').innerHTML = '<i class="far fa-comment-alt"></i> My Time Machine(' + total + ')'
}
page += 1
}).then(() => {
bb();
if (nowNum < total) {
document.getElementById('bibi').innerHTML += '<button id="more" onclick="getNew()">再翻翻</button>'
}
document.getElementById('bibi').removeChild(document.getElementById('loading'))
})
}
*/
// 获取数据
function getNew() {
let bibi = document.getElementById('bibi');
try {
bibi.removeChild(document.getElementById('more'))
} catch (error) {}

bibi.innerHTML += '<div id="loading">正在加载中...</div>';

let pageSize = 12; // 修改为你想要获取的数据条数
let requestUrl = Url + page + '&pageSize=' + pageSize; // 修改 URL,添加 pageSize 参数

fetch(requestUrl)
.then(res => res.json())
.then((res) => {
total = res.data.total;
items = res.data.items;
nowNum += items.length;
if (page == 1) {
document.querySelector('.bb-info').innerHTML = '<i class="far fa-comment-alt"></i> My Time Machine(' + total + ')';
}
page += 1;
})
.then(() => {
bb();
if (nowNum < total) {
document.getElementById('bibi').innerHTML += '<button id="more" onclick="getNew()">再翻翻</button>';
}
document.getElementById('bibi').removeChild(document.getElementById('loading'));
});
}

// 渲染数据
function bb() {
let bb = document.getElementById('bb-main')
items.forEach((item) => {
let time = item.createdAt.substring(0, 10);
let div = document.createElement('div')
item.content = contentFormat(item.content)

div.className = 'bb-card'
div.innerHTML = '<div class="card-header"><div class="avatar"><img class="nofancybox"src="' + item.author.avatar + '"></div><div class="name">' + item.author.nickName + '</div>' + svg + '<div class="card-time">' + time + '</div></div><div class="card-content">' + item.content + ''
bb.appendChild(div)
})
}

// content格式化
function contentFormat(s) {
let br = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
let re_forimg = /<img(.*?)src=[\"|\']?(.*?)[\"|\']?(.*?)>|!\[(.*?)\]\((.*?)\)/g;
let getImgUrl = /(http(.*).[jpg|png|gif])/g;
let ls = s.match(getImgUrl)
s = s.replace(re_forimg, '')
s = s.replace(br, '')

let html = '<br>'
if (ls) {
ls.forEach((e) => {
html += '<a href="' + e + '" target="_blank" data-fancybox="group" class="fancybox"><img src="' + e + '"></a>'
})
}
s += html
return s
}