想法来自 Vino 大佬的博客,我觉得使用一个 Loading 页面来缓解博客渲染速度慢带来的尴尬是件酷酷的事情。自己捣鼓了一下如何把任何一个页面改成 Hexo 博客下的 Loading 页面,发现其实还是比较简单的。

下面我来说一下我魔改的具体步骤。

一、制作 Loading 页面

  1. 首先我们需要准备一个已经写好的 Loading 动画页面。
    (这种动画页面网上有很多大佬提供了开源项目,咋就不重复造轮子了,嘿嘿~)

我这里以大佬 YanH 写的 Loading 动画页面为例。

其页面具体代码如下:

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
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">

<title>带LOGO的全屏加载动画</title>
<link rel="stylesheet" href="118.css">
</head>

<body>
<div class="loader-wrapper">
<div class="loader"><img src="/images/1.png" alt=""></div>
<div class="loader-text">
<!-- 10个div -->
<div>L</div>
<div>O</div>
<div>A</div>
<div>D</div>
<div>I</div>
<div>N</div>
<div>G</div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</body>

</html>
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
*{
/* 初始化 */
margin: 0;
padding: 0;
}
body{
/* 100%窗口高度 */
height: 100vh;
}
.loader-wrapper{
/* 固定定位 */
position: fixed;
left: 0;
top: 0;
z-index: 1;
width: 100%;
height: 100%;
/* 溢出隐藏 */
overflow: hidden;
/* 渐变背景 */
background: linear-gradient(45deg,rgb(90,54,148) 0%,rgb(19,189,206) 33%,rgb(0,148,217) 66%,rgb(111,199,181) 100%);
background-size: 400%;
background-position: 0% 100%;
/* 执行背景渐变动画:动画名 时长 加速后减速 无限次播放 */
animation: gradient 7.5s ease-in-out infinite;
}
/* 旋转loading的外圈 */
.loader{
width: 150px;
height: 150px;
border: 3px solid transparent;
border-top-color: #fff;
/* 相对定位 居中 */
position: relative;
left: 50%;
top: 50%;
margin-left: -75px;
margin-top: -75px;
z-index: 2;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
/* 执行旋转动画 */
animation: spin 1.7s linear infinite;
}
/* 旋转loading的中圈 */
.loader::before{
content: "";
/* 绝对定位 */
position: absolute;
top: 5px;
left: 5px;
bottom: 5px;
right: 5px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #fff;
/* 执行反向的旋转动画 reverse:反向 */
animation: spin 0.6s linear infinite reverse;
}
/* 旋转loading的内圈 */
.loader::after{
content: "";
/* 绝对定位 */
position: absolute;
top: 15px;
left: 15px;
bottom: 15px;
right: 15px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #fff;
/* 执行旋转动画 */
animation: spin 1s linear infinite;
}
/* logo */
.loader img{
width: 55%;
height: 55%;
border-radius: 50%;
/* 执行反向的旋转动画,时长必须和外圈的动画一致(不让其跟着旋转) */
animation: spin 1.7s linear infinite reverse;
}
.loader-text{
width: 50%;
height: 36px;
/* 绝对定位 水平居中 */
position: absolute;
top: 72%;
left: 50%;
transform: translateX(-50%);
z-index: 3;
/* 防止选取 */
user-select: none;
}
.loader-text div{
width: 30px;
height: 36px;
color: #fff;
font-size: 32px;
margin: 0 20px;
/* 绝对定位 */
position: absolute;
/* 默认隐藏+旋转180度 */
opacity: 0;
transform: rotate(180deg);
/* 执行文字移动动画 */
animation: move 2s linear infinite;
}
/* 最后面的三个圆 */
.loader-text div:nth-child(8)::before,
.loader-text div:nth-child(9)::before,
.loader-text div:nth-child(10)::before{
content: "";
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #fff;
position: absolute;
left: 0;
bottom: 0;
}
/* 文字下的投影 */
.loader-text div::after{
content: "";
width: 10px;
height: 5px;
border-radius: 50%;
background-color: rgba(255,255,255,0.15);
position: absolute;
bottom: -40px;
left: 50%;
margin-left: -5px;
}
/* 最后面的三个圆的投影 */
.loader-text div:nth-child(8)::after,
.loader-text div:nth-child(9)::after,
.loader-text div:nth-child(10)::after{
left: 0;
margin-left: 0;
}
/* 接下来为各个文字设置动画延迟时间 */
.loader-text div:nth-child(2){
animation-delay: 0.2s;
}
.loader-text div:nth-child(3){
animation-delay: 0.4s;
}
.loader-text div:nth-child(4){
animation-delay: 0.6s;
}
.loader-text div:nth-child(5){
animation-delay: 0.8s;
}
.loader-text div:nth-child(6){
animation-delay: 1s;
}
.loader-text div:nth-child(7){
animation-delay: 1.2s;
}
.loader-text div:nth-child(8){
animation-delay: 1.4s;
}
.loader-text div:nth-child(9){
animation-delay: 1.6s;
}
.loader-text div:nth-child(10){
animation-delay: 1.8s;
}

/* 定义动画 */
/* 背景渐变动画 */
@keyframes gradient {
50%{
background-position: 100% 0%;
}
}
/* 旋转动画 */
@keyframes spin {
0%{
transform: rotate(0);
}
100%{
transform: rotate(360deg);
}
}
/* 文字移动动画 */
@keyframes move {
0%{
right: 0;
opacity: 0;
}
35%{
right: 41%;
opacity: 1;
transform: rotate(0);
}
65%{
right: 59%;
opacity: 1;
transform: rotate(0);
}
100%{
right: 100%;
transform: rotate(-180deg);
}
}
  1. 适配手机样式。一定要注意手机样式是否显示正常,如果不正常可以通过如下代码进行重新调整。
1
2
3
4
5
6
7
8
9
10
11
12
/*小屏幕下(手机类)的样式*/
@media only screen and (max-width: 601px) {
/* 你的代码 */
}
/*中等屏幕下(平板类)的样式*/
@media only screen and (min-width: 600px) and (max-width: 992px) {
/* 你的代码 */
}
/*大屏幕下(桌面类)的样式*/
@media only screen and (min-width: 993px) {
/* 你的代码 */
}
  1. 最后注意调整 Loading 页面层级,使其在所有页面的最上面。
1
2
3
.loader-wrapper {/* 注意选择器要改成你的 Loading 页面 */
z-index: 10000/* 填写适合你自己博客的数字,确保 Loading 页面在所有页面最上面 */;
}

二、引入自己的博客

修改好了 Loading 动画页面后就可以引入自己的博客中了。

  1. 首先,在主题文件夹中的 \layout\_widget\ 文件夹里创建一个 loading.ejs 文件。

图2.1 loading.ejs

  1. 用编辑器打开该文件,写入以下代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
<% if (theme.preloader.enable) { %>
<div id="loader-box">
/* 你的 HTML 代码将放在这里 */

<script>
var endLoading = function () {
document.body.style.overflow = 'auto';
document.getElementById('loader-box').remove();
}
window.addEventListener('load',endLoading);
</script>
</div>
<% } %>
  1. 打开准备的 Loading 动画 HTML 文件,将 <body> 标签下的所有内容复制到第 2 步注释标注的位置。

图2.2 Loading 页面代码

  1. 在主题目录下的 source 文件夹里找到 css 文件夹,新建一个 loading.css 文件,并将前面修改好的 CSS 文件内容复制进去、保存。

图2.3 loading.ejs

  1. 然后打开主题目录下的 _config.yml 文件,添加如下代码,增加一个控制 Loading 页面的开关。
1
2
3
# 是否开启页面加载动画
preloader:
enable: true
  1. 接着在主题目录下的 _config.yml 找到 libs 的配置项,在 css 子项里添加自己的 loading.css 文件位置信息。参考代码如下。
1
2
3
libs:
css:
loadingPage: /css/loading.css
  1. 紧接着我们就可以在页面中引用相关文件了。
  • 打开 layout\_partial\head.ejs 文件,在 <head> 标签里添加代码:
1
2
3
4
<!--自定义添加的 Loading Page CSS 样式-->
<% if (theme.preloader.enable) { %>
<link rel="stylesheet" type="text/css" href="<%- theme.jsDelivr.url %><%- theme.libs.css.loadingPage %>">
<% } %>
  • 最后我们打开 layout\layout.ejs 文件,在 <body> 标签下最前的位置添加代码:
1
2
3
4
<!--自定义的 Loading Page-->
<% if (theme.preloader.enable) { %>
<%- partial('_widget/loading') %>
<% } %>

三、部署

hexo cl && hexo g && hexo d 一键三连即可。具体一些细节需要根据自己的需求自己修改解决,这里只提供一个自定义 Loading 页面的大体思路,希望大家能自己思考,做出自己风格的独特 Blog,嘿嘿(●ˇ∀ˇ●)~

溜了~

四、【更新】优化判断算法

这个嘛,前面给的算法写在 loading.ejs 里是为了代码模块化,尽量相关的代码都写在一起。

之前的算法
1
2
3
4
5
6
7
<script>
var endLoading = function () {
document.body.style.overflow = 'auto';
document.getElementById('loader-box').remove();
}
window.addEventListener('load',endLoading);
</script>

所以,最开始提供的算法是通过监听 ‘load’ 时间来完成的,也就是说 Loading 页面必须是在当前页面中所有资源都加载完毕后才关闭的。

这样一来,就会产生一个小问题:我们希望 Loading 页面是在我们可见资源(也就是页面显示的内容)都加载完毕后就立刻关闭,而不是还要等一些无关紧要的东西加载完毕才关闭。

那么,为了优化这一点,我们必须在之前的代码上做点小改动!(因为我有懒图加载,所有 Loading 页面不会被图片加载阻塞)

  1. 首先,将之前的算法代码删除
  2. 来到主题目录里的 layout.ejs 文件,在 <body> 标签的最后位置添加如下代码:
服务器慢的(注意添加位置)
1
2
3
<script id="removeLoading">
document.getElementById('loader-box').remove();
</script>
  1. 然后给不必要的 JS 脚本(自己判断)加上 asyncdefer 属性。【相关知识请看此文章

注意一个细节:
如果你的服务器非常给力,页面全部资源的加载速度可以达到 1s 以内的话建议不要这么做。因为你的 Loading 页面会一闪而过,甚至看不清楚是什么东西。

建议访问速度特别快的在原方法里做些小改动即可:

服务器给力的
1
2
3
4
5
6
7
8
var endLoading = function () {
document.body.style.overflow = 'auto';
// 利用 setTimeout 函数延长 Loading 页面显示的时间
setTimeout(function(){
document.getElementById('loader-box').remove();
}, 1000 /* 单位:毫秒 */ );
}
window.addEventListener('load',endLoading);