并非所有想表达或分享的东西都适合写成长文,“即刻短文”可以避免博客短文章过多造成的整站文章质量下降。

最近由于未知原因,域名半寄,Artitalk 用不了了。无意间看到 即刻短文静态部署版,遂准备尝试。

实际上先前以多次尝试,又应种种原因不了了之。本次成功,记以备忘。本文所述已按照自用情况进行一定的修改,效果与别人的版本有出入,请慎重使用。

为书写方便,下文如无其他说明,则默认 Hexo 项目根目录为【Blogroot】。测试使用 Butterfly 主题,其他主题未尝试。

创建数据

进入【Blogroot】/source/_data目录,创建essay.yml,其中数据示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- class_name: 即刻短文
essay_list:
- content: test
date: 2024/3/30
- content: test
date: 2024/3/5
- content: 链接示例
date: 2024/1/25
link: https://info.cern.ch/
- content: 发布者名称
date: 2023/10/23 08:00:00
from: Author
- content: 图片测试
date: 2022/10/23 10:00:00
image:
- https://api.vvhan.com/api/bing
- content: ThreeJs API 真多丫
date: 2022/10/19
- content: 歌曲推荐
date: 2022/09/25
aplayer:
server: netease
id: 3949477

参数:

参数 备选值/类型 释义
class_name String 标识符,无实际意义
essay_list Array 【必选】即刻短文数据列表
essay_list.content String 必选】短文 文字内容
essay_list.date Time 【必选】发布时间 格式建议为2022/10/10 00:00:00
essay_list.image Array 片内容,可填写多张图片
essay_list.from String 来源,也可以是任何标识
essay_list.link String 外部链接
essay_list.aplayer Array 单曲音乐,需 aplayer 支持
essay_list.aplayer.server String 【essay_list.aplayer 后必选】音乐服务器
essay_list.aplayer.id String 【essay_list.aplayer 后必选】单曲 id

创建单页

进入【Blogroot】/source,新建文件夹essay并在该文件夹下创建index.md(此处文件夹名称可自定义,之后访问路径需与此相同),在该文件中写入:

1
2
3
4
5
6
7
---
title: 即刻短文
comments: true
aside: false
top_img: /img/essay_top_img.png
type: essay
---

创建 DOM 文件

进入【Blogroot】/themes/butterfly/layout/includes/page目录,创建essay.pug文件,写入:

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
#essay_page
#bber
section.timeline.page-1
ul#waterfall.list
each i in site.data.essay
each item, index in i.essay_list
if index < 30
li.bber-item
.bber-content
p.datacont= item.content
if item.image
.bber-container-img
each iten, indey in item.image
a.bber-content-img(href=item.image[indey], target="_blank", data-fancybox="gallery", data-caption="")
img(src=item.image[indey])
.bber-content-noimg
if item.aplayer
.bber-music
.aplayer.no-destroy(data-id=item.aplayer.id data-server=item.aplayer.server data-type="song" data-order="list" data-preload="none" data-autoplay="false" data-mutex="true" data-theme='var(--blogessay-main)')
hr
.bber-bottom
.bber-info
.bber-info-time
- var datedata = new Date(item.date).toISOString()
i.far.fa-clock
time.datatime(datetime= item.date)= datedata
if item.link
a.bber-content-link(target="_blank", title="跳转到短文指引的链接", href=item.link, rel="external nofollow")
i.fas.fa-link
| 链接
if item.from
.bber-info-from
i.fas.fa-fire
span=item.from
.bber-reply(onclick="anzhiyu.commentText(" + `'${item.content}'` + ")")
i.fa-solid.fa-message
#bber-tips(style='color: var(--blogessay-secondtext);')
| - 只展示最近 30 条短文 -

修改文件

【Blogroot】/themes/butterfly/layout中找到page.pug并编辑(上下无关代码已省去):

1
2
3
4
5
6
7
    case page.type
+ when 'essay'
+ include includes/page/essay.pug
when 'tags'
include includes/page/tags.pug
when 'categories'
include includes/page/categories.pug

CSS 与 JS

CSS

【Blogroot】/source/css目录下创建essay.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* 配色部分,参考 anzhiyu */
:root {
--blogessay-theme-op: #4259ef23;
--blogessay-gray-op: #9999992b;
--blogessay-theme-top: var(--blogessay-theme);
--blogessay-white: #fff;
--blogessay-white-op: rgba(255, 255, 255, 0.2);
--blogessay-gray: #999999;
--blogessay-main: var(--blogessay-theme);
--blogessay-main-op: var(--blogessay-theme-op);
--blogessay-shadow-border: 0 8px 16px -4px #2c2d300c;
--blogessay-style-border: 1px solid var(--blogessay-card-border);
--blogessay-style-border-hover: 1px solid var(--blogessay-main);
--blogessay-style-border-avatar: 4px solid var(--blogessay-background);
}

[data-theme="light"] {
--blogessay-theme: #3b70fc;
--blogessay-theme-deep: #1856fb;
--blogessay-theme-op: #4259ef23;
--blogessay-fontcolor: #363636;
--blogessay-background: #f7f9feCC;
--blogessay-secondbg: #f1f3f8;
--blogessay-card-bg: #ffffff;
--blogessay-card-border: #e3e8f7;
}

[data-theme="dark"] {
--blogessay-theme: #0084ff;
--blogessay-theme-deep: #0076e5;
--blogessay-theme-op: #0084ff23;
--blogessay-fontcolor: #f7f7fa;
--blogessay-background: #18171d00;
--blogessay-secondbg: #30343f;
--blogessay-card-bg: #000000;
--blogessay-card-border: #42444a;
}

#page:has(#essay_page) {
border: 0;
box-shadow: none !important;
padding: 0 !important;
background: transparent !important;
}
#page:has(#essay_page) .page-title {
display: none;
}
#web_bg ~ .page:has(#essay_page) {
background: var(--blogessay-background);
}
#bber .bber-container-img {
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
flex-wrap: wrap;
margin-bottom: 0.3rem;
}
#bber .bber-container-img .bber-content-noimg {
width: calc(100% / 4 - 5px);
}

#bber .bber-content-img img {
object-fit: cover;
max-height: 100%;
border-radius: 12px;
}

#bber .bber-content-img {
height: 100px;
border-radius: 12px;
overflow: hidden;
display: flex;
position: relative;
width: calc(100% / 4 - 5px);
margin-bottom: 10px;
}

#bber .bber-content .datacont {
order: 0;
font-size: 0.8rem;
font-weight: 700;
color: var(--blogessay-fontcolor);
width: 100%;
line-height: 1.38;
border-radius: 12px;
margin-bottom: 0.5rem;
display: flex;
flex-direction: column;
text-align: justify;
}
#bber p {
margin: 0px;
}
#bber div.bber-content {
display: flex;
flex-flow: wrap;
border-radius: 12px;
width: 100%;
height: 100%;
}
#bber .timeline ul li.bber-item {
position: relative;
width: 32%;
border: var(--blogessay-style-border-always);
border-radius: 12px;
padding: 1rem 1rem 0.5rem;
transition: all 0.3s ease 0s;
display: flex;
flex-flow: column nowrap;
justify-content: space-between;
align-items: flex-start;
background: var(--blogessay-card-bg);
box-shadow: var(--blogessay-shadow-border);
margin-right: 2%;
}
#bber .timeline #waterfall.show {
opacity: 1;
}
#bber .timeline #waterfall {
opacity: 0;
transition: all 0.3s ease 0s;
}
#bber ul.list {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
#bber {
margin-top: 1rem;
width: 100%;
}
#bber > section > ul > li.bber-item {
margin-bottom: 1rem;
}

#bber-tips {
font-size: 14px;
display: flex;
justify-content: center;
margin-top: 1rem;
}

#bber .timeline ul li.bber-item hr {
display: flex;
position: relative;
margin: 8px 0px;
border: 1px dashed var(--blogessay-theme-op);
width: 100%;
}

#bber .bber-info {
display: flex;
align-items: center;
}

#bber > section > ul > li > div .bber-info-time,
#bber > section > ul > li > div .bber-info-from {
color: var(--blogessay-fontcolor);
font-size: 0.7rem;
background-color: var(--blogessay-gray-op);
padding: 0px 8px;
border-radius: 20px;
cursor: default;
display: flex;
align-items: center;
}

#bber .bber-info .far.fa-clock {
margin-right: 4px;
}
#bber > section > ul > li > div .bber-info-from span,
#bber > section > ul > li > div .bber-info-from {
margin-left: 4px;
}

#bber .bber-bottom {
display: flex;
justify-content: space-between;
width: 100%;
margin-top: 10px;
}

#bber .bber-bottom .bber-reply {
cursor: pointer;
}

#bber .timeline ul li.bber-item:hover {
border: var(--blogessay-style-border-hover);
}

#bber .bber-content-link {
display: flex;
margin-left: 0.5rem;
font-size: 0.7rem;
align-items: center;
background-color: rgba(245, 108, 108, 0.13);
color: rgb(245, 108, 108);
padding: 0px 8px;
border-radius: 20px;
}
#bber .bber-content-link i {
margin-right: 3px;
}
#bber .bber-content-link:hover {
background-color: var(--blogessay-main);
color: var(--blogessay-white);
}
#bber .bber-music {
width: 100%;
height: 90px;
margin: 0.5rem 0;
border-radius: 8px;
overflow: hidden;
border: var(--blogessay-style-border-always);
background: var(--blogessay-secondbg);
}
#bber .aplayer {
margin: 0;
}

#bber .aplayer.aplayer-withlrc .aplayer-pic {
height: 82px;
width: 82px;
margin: 4px;
border-radius: 4px;
}
.bber-music .aplayer.aplayer-withlrc .aplayer-info {
padding: 5px 7px 0;
}
#bber .aplayer .aplayer-info .aplayer-music {
height: 23px;
}
#bber .aplayer .aplayer-info .aplayer-music .aplayer-title {
font-size: 0.8rem;
font-weight: 700;
margin: 0;
color: var(--blogessay-fontcolor);
}

#bber .aplayer .aplayer-info .aplayer-controller {
align-items: center;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap {
padding: 0;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-time {
position: initial;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar {
background: var(--blogessay-gray);
height: 8px;
border-radius: 12px;
transition: 0.3s;
overflow: hidden;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded {
height: 100%;
border-radius: 12px;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played {
height: 100%;
border-radius: 12px;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {
display: none;
}
#bber .aplayer .aplayer-info .aplayer-controller .aplayer-time {
position: initial;
}

/* 响应式 */
@media screen and (max-width: 1300px) {
#bber .timeline ul li.bber-item {
width: 49%;
margin-right: 1%;
}
}
@media screen and (max-width: 768px) {
#bber .timeline ul li.bber-item {
width: 100%;
margin-right: 0px;
}
}
[data-theme="dark"] #bber .bber-music .aplayer,
[data-theme="dark"] #bber .aplayer .aplayer-lrc:before,
[data-theme="dark"] #bber .aplayer .aplayer-lrc:after {
background: var(--blogessay-card-bg);
color: var(--blogessay-fontcolor);
}
#bber .aplayer .aplayer-lrc p {
color: var(--blogessay-fontcolor);
}
核心 JS

【Blogroot】/source/js目录下创建essay.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
var percentFlag = false; // 节流阀
function essayScroll() {
let a = document.documentElement.scrollTop || window.pageYOffset; // 卷去高度
const waterfallResult = a % document.documentElement.clientHeight; // 卷去一个视口
result <= 99 || (result = 99);

if (
!percentFlag &&
waterfallResult + 100 >= document.documentElement.clientHeight &&
document.querySelector("#waterfall")
) {
// console.info(waterfallResult, document.documentElement.clientHeight);
setTimeout(() => {
waterfall("#waterfall");
}, 500);
} else {
setTimeout(() => {
document.querySelector("#waterfall") && waterfall("#waterfall");
}, 500);
}

const r = window.scrollY + document.documentElement.clientHeight;

let p = document.getElementById("post-comment") || document.getElementById("footer");

(p.offsetTop + p.offsetHeight / 2 < r || 90 < result) && (percentFlag = true);
}
function replaceAll(e, n, t) {
return e.split(n).join(t);
}
var blogessay = {
diffDate: function (d, more = false) {
const dateNow = new Date();
const datePost = new Date(d);
const dateDiff = dateNow.getTime() - datePost.getTime();
const minute = 1000 * 60;
const hour = minute * 60;
const day = hour * 24;
const month = day * 30;

let result;
// Check if the suffix object and required properties exist
const suffix = GLOBAL_CONFIG.date_suffix || {};
const daySuffix = suffix.day || '天前';
const hourSuffix = suffix.hour || '小时前';
const minSuffix = suffix.hour || '分钟前';

if (more) {
const monthCount = dateDiff / month;
const dayCount = dateDiff / day;
const hourCount = dateDiff / hour;
const minuteCount = dateDiff / minute;

if (monthCount >= 1) {
result = datePost.toLocaleDateString().replace(/\//g, "-");
} else if (dayCount >= 1) {
result = parseInt(dayCount) + " " + daySuffix;
} else if (hourCount >= 1) {
result = parseInt(hourCount) + " " + hourSuffix;
} else if (minuteCount >= 1) {
result = parseInt(minuteCount) + " " + minSuffix;
} else {
result = suffix.just;
}
} else {
result = parseInt(dateDiff / day);
}
return result;
},
changeTimeInEssay: function () {
document.querySelector("#bber") &&
document.querySelectorAll("#bber time").forEach(function (e) {
var t = e,
datetime = t.getAttribute("datetime");
(t.innerText = blogessay.diffDate(datetime, true)), (t.style.display = "inline");
});
},
reflashEssayWaterFall: function () {
document.querySelector("#waterfall") &&
setTimeout(function () {
waterfall("#waterfall");
document.getElementById("waterfall").classList.add("show");
}, 500);
},
commentText: function (e) {
if (e == "undefined" || e == "null") e = "好棒!";
var n = document.getElementsByClassName("el-textarea__inner")[0],
t = document.createEvent("HTMLEvents");
if (!n) return;
t.initEvent("input", !0, !0);
var o = replaceAll(e, "\n", "\n> ");
(n.value = "> " + o + "\n\n"), n.dispatchEvent(t);
var i = document.querySelector("#post-comment").offsetTop;
window.scrollTo(0, i - 80),
n.focus(),
n.setSelectionRange(-1, -1),
document.getElementById("comment-tips") && document.getElementById("comment-tips").classList.add("show");
},
};

blogessay.changeTimeInEssay();
blogessay.reflashEssayWaterFall();

若直接按照 即刻短文(瀑布流)部署方案 提供的custom.js可能会出现essay.ymldate日期距今不足 30 日导致页面渲染出错的问题。对于那个文件,折中方案可以这样:

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
var blogessay = {
diffDate: function (d, more = false) {
const dateNow = new Date();
const datePost = new Date(d);
const dateDiff = dateNow.getTime() - datePost.getTime();
const minute = 1000 * 60;
const hour = minute * 60;
const day = hour * 24;
const month = day * 30;

let result;
+ const monthCount = dateDiff / month;
+ const dayCount = dateDiff / day;
+ const hourCount = dateDiff / hour;
+ const minuteCount = dateDiff / minute;

if (more) {
const monthCount = dateDiff / month;
const dayCount = dateDiff / day;
const hourCount = dateDiff / hour;
const minuteCount = dateDiff / minute;

if (monthCount >= 1) {
result = datePost.toLocaleDateString().replace(/\//g, "-");
} else if (dayCount >= 1) {
- result = parseInt(dayCount) + " " + GLOBAL_CONFIG.date_suffix.day;
+ result = parseInt(dayCount) + " " + daySuffix;
} else if (hourCount >= 1) {
- result = parseInt(hourCount) + " " + GLOBAL_CONFIG.date_suffix.hour;
+ result = parseInt(hourCount) + " " + hourSuffix;
} else if (minuteCount >= 1) {
- result = parseInt(minuteCount) + " " + GLOBAL_CONFIG.date_suffix.min;
+ result = parseInt(minuteCount) + " " + minSuffix;
} else {
- result = GLOBAL_CONFIG.date_suffix.just;
+ result = suffix.just;
}
} else {
result = parseInt(dateDiff / day);
}
return result;
},
waterfall.js

【Blogroot】/source/js目录下创建waterfall.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
function waterfall(a) {
function b(a, b) {
var c = window.getComputedStyle(b);
return parseFloat(c["margin" + a]) || 0;
}
function c(a) {
return a + "px";
}
function d(a) {
return parseFloat(a.style.top);
}
function e(a) {
return parseFloat(a.style.left);
}
function f(a) {
return a.clientWidth;
}
function g(a) {
return a.clientHeight;
}
function h(a) {
return d(a) + g(a) + b("Bottom", a);
}
function i(a) {
return e(a) + f(a) + b("Right", a);
}
function j(a) {
a = a.sort(function (a, b) {
return h(a) === h(b) ? e(b) - e(a) : h(b) - h(a);
});
}
function k(b) {
f(a) != t && (b.target.removeEventListener(b.type, arguments.callee), waterfall(a));
}
"string" == typeof a && (a = document.querySelector(a));
var l = [].map.call(a.children, function (a) {
return (a.style.position = "absolute"), a;
});
a.style.position = "relative";
var m = [];
l.length && ((l[0].style.top = "0px"), (l[0].style.left = c(b("Left", l[0]))), m.push(l[0]));
for (var n = 1; n < l.length; n++) {
var o = l[n - 1],
p = l[n],
q = i(o) + f(p) <= f(a);
if (!q) break;
(p.style.top = o.style.top), (p.style.left = c(i(o) + b("Left", p))), m.push(p);
}
for (; n < l.length; n++) {
j(m);
var p = l[n],
r = m.pop();
(p.style.top = c(h(r) + b("Top", p))), (p.style.left = c(e(r))), m.push(p);
}
j(m);
var s = m[0];
a.style.height = c(h(s) + b("Bottom", s));
var t = f(a);
window.addEventListener ? window.addEventListener("resize", k) : (document.body.onresize = k);
}

之后编辑根目录下_config.butterfly.yml文件,在inject:将这三个文件引入:

1
2
3
4
5
6
7
8
9
10
inject:
head:
# ...
- <link rel="stylesheet" href="/css/essay.css"/>
# ...
bottom:
# ...
- <script async data-pjax src="/js/essay.js"></script>
- <script async data-pjax src="/js/waterfall.js"></script>
# ...

之后执行 Hexo 三连即可生效。

参考:

https://blog.zhheo.com/p/557c9e72.html
https://blog.anheyu.com/posts/c248.html
https://meuicat.com/blog/67/index.html