前言

在开始之前,先感谢小康大佬栽树,好让我们乘凉。

  • 为什么要更换?
    因为腾讯云开发要收费了,我想白嫖
  • 为什么不换其他的?
    因为用习惯了,感觉很好用。
  • 为什么…
    给爷打住

先部署

部署的话就跟着官方文档走就可以了,基本不会出什么问题。

这里说一下我遇见的一些小问题:

  • 弄后台填写环境变量时直接复制粘贴,结果多了一个斜杠,后台会登陆不上,要注意一下
    例如让填:https://kkapi-open.vercel.app
    然后我填成了:https://kkapi-open.vercel.app/
  • 填写变量时,mongoDB的账号密码不需要填写
    mongodb的url里面已经有账号和密码了,所以变量只需要填url和那个加密的即可,加密的内容是随便填的。

前端

小康大佬是写了前端方案的,在这查看
但是功能太多,例如有评论功能等。我并不需要这些,而且直接引用的话就多多少少会出一些莫名其妙的Bug,所以我就自己写了js,样式直接照抄。

我的js和css仅适合我自己,不一定适合你,我后期可能会根据我的需求再进行修改等等,所以在这主要是给你提供简单的思路,可以让你根据自己需求写代码。

js和css文件创建和引入问题看这篇文章:Hexo博客添加自定义css和js文件

首页轮播

首页轮播样式是混合抄的,会css和js的自己进行更改就可以,很简单。
我是直接复制的我的css,你粘贴之后有的地方可能会不一样,自行修改即可,不会的话也可以留言,我帮你看看

修改源码

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

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

block content
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts
+ #bber-talk
+ link(rel="stylesheet", href="/css/bbtalk.css")
+ script(src='/js/timeago.min.js')
+ script(src='/js/bbtalk.js')
+postUI
include includes/pagination.pug

bbtalk.css

在source/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
/* 首页轮播 */

#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;
}

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

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

#bber-talk .talk-list {
max-height: 32px;
font-size: 16px;
overflow: hidden;
}

#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;
}

#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/js目录下创建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-xi.vercel.app/api/ispeak?author=62cfe22a3a91f6ac8ea6803f' // 在这修改api

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

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 = '<span class="datatime">' + dataTime + '</span>'

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/js目录下创建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和css

1
2
3
4
5
6
7
8
9
10
11
12
13
---
title: 哔哔
date: 2021-10-17 16:36:12
type: 'bb'
comments: false
aside: false
---
+ <link rel="stylesheet" href="/css/bbtalk.css"/>
+ <script src="/js/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


/* 哔哔页面 */

#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: rgba(255, 255, 255, 0.1);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.06);
overflow: hidden;
margin-top: 20px;
transition: all 0.25s;
user-select: none;
}

#bibi .bb-card:hover {
box-shadow: 0 5px 10px 8px #07111b29;
transform: translateY(-3px)
}

#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;
}

#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%;
}
}

bibi.js

在source/js目录下创建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
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-open-xi.vercel.app/api/ispeak?author=62cfe22a3a91f6ac8ea6803f&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"><img src="/img/loading.gif" alt="loading"></div>' // loading图片可以f12在我网站源码下载,也可以使用其他图片。

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 bibi(' + 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 + '</div><div class="card-footer"><div data-v-185689ea=""class="card-label"style="background: ' + item.tag.bgColor + '; color: white;">' + item.tag.name + '</div></div>'
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
}

后记

如果你想使用更多的功能,建议使用小康大佬写的前端方案。
如果你和我一样只是想实现简单的纯粹的哔哔功能,那么你可以参考我的再进行修改优化等等。
注意,只是进行参考,不建议直接使用,我写的代码仅仅只是在我网站上面能跑,在你的网站上不一定适用。