抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

無名小栈

站点重构中

本文基于 Hexo + Volantis,文中提到的文件路径可能与您的项目路径并不相同

一个锦上添花的小功能,能更直观的向访客展示网站当前状态或显示信息,这篇文章就来说说如何给你的博客添加 izitoast 弹窗通知插件。

功能介绍

可及时反馈操作结果,提升访客浏览体验。弹窗具体样式可参考本站,或点击下方按钮查看一些示例:

复制提醒 错误提醒 音乐通知 全屏通知 常驻通知

引入文件

最新的 Volantis dev 版本已经内置该弹窗,具体操作步骤请参考官方配置文档,此处不再赘述

这里有两种引入方法,分为外部引入和本地引入。为了不改动源码,最好还是选择外部引入方式。

Volantis 主题用户可直接在根目录下的 _config.yml 中添加以下代码:

_config.yml
1
2
3
4
5
import:
link:
# 引入 izitoast 弹窗
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/izitoast@1.4.0/dist/css/iziToast.min.css">
- <script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/izitoast@1.4.0/dist/js/iziToast.min.js"></script>

其他情况请将此代码引入合适的地方:

1
2
3
4
5
6
7
8
9
<head>
...
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/izitoast@1.4.0/dist/css/iziToast.min.css">
...
</head>
<body>
...
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/izitoast@1.4.0/dist/js/iziToast.min.js"></script>
</body>

添加弹窗

避免冲突

下面的操作涉及修改源码,若不进行正确操作,则可能会在更新主题时遇到与官方分支相差太大从而无法更新,所以在修改时最好做好记录,以便在发生冲突时及时找到原因。

一个避免合并冲突的小方法

若你使用的是 Volantis 主题,关于下文提到的在 </body> 标签前加入代码,可在 themes\volantis\layout\_partial\scripts 目录下新建一个 custom.ejs ( 名称随意 ) 文件,并在 themes\volantis\layout\_partial\scripts\index.ejs 中添加

1
<%- partial('custom') %>

后续的 <script> 代码都可以写进该文件。

你也可以参考该 issues 来正确修改主题。

复制提醒

</body> 标签前加入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
document.body.oncopy = function () {
iziToast.info({
timeout: 4000, // 关闭弹窗的时间
icon: 'Fontawesome', // 图标类别
closeOnEscape: 'true', // 允许使用Esc键关闭弹窗
transitionIn: 'bounceInLeft', // 弹窗打开动画
transitionOut: 'fadeOutRight', // 弹窗关闭动画
displayMode: 'replace', // 替换已经打开的弹窗
layout: '2', // Medium模式
position: 'topRight', // 弹窗位置
icon: 'fad fa-copy', // 图标类名
backgroundColor: '#fff', // 弹窗背景色
title: '复制成功', // 通知标题
message: '请遵守 CC BY-NC-SA 4.0 协议' // 通知消息内容
});
}
</script>

音乐通知

音乐通知弹窗目前仅适用于 Volantis 主题

themes\volantis\source\js\aplayer.js 文件的 34 行后添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var index = document.querySelector('meting-js').aplayer.list.index;
var title = document.querySelector('meting-js').aplayer.list.audios[index].title;
var artist = document.querySelector('meting-js').aplayer.list.audios[index].artist;
iziToast.info({
timeout: 4000,
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-play-circle',
backgroundColor: '#fff',
title: '音乐通知',
message: '正在播放:' + title + ' - ' + artist
});

特殊纪念日通知

进行这一步前请确定已经引入了 iziToast 弹窗

</body> 标签前加入以下代码:

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
<script>
var myDate = new Date;
var mon = myDate.getMonth() + 1;
var date = myDate.getDate();
var days = ['4.4', '5.12', '7.7', '9.9', '9.18', '12.13']; // 自定义纪念日
for (var day of days) {
var d = day.split('.');
if (mon == d[0] && date == d[1]) {
iziToast.info({
timeout: 14000,
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-candle-holder',
backgroundColor: '#fff',
title: '今天是国家纪念日',
message: '历史不会忘记,人民永远铭记!<p style="margin-top: 4px;">全站已切换为黑白模式</p>'
});
document.write('<style>html{-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%);-ms-filter:grayscale(100%);-o-filter:grayscale(100%);filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);_filter:none}</style>')
break;
}
}
</script>

自动明暗切换通知

进行这一步前请对源文件做好备份并且确定已经引入了 iziToast 弹窗

使用下方代码替换 themes\volantis\layout\_partial\scripts\darkmode.ejs

自动夜间模式 + iziToast 弹窗适配
themes\volantis\layout\_partial\scripts\darkmode.ejs
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
294
295
296
297
298
299
300
301
<!--自动夜间模式-->
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/Colsrch/CDN@master/judge_time/js.js"></script>

<script>
const rootElement = document.documentElement;
const darkModeStorageKey = "user-color-scheme";
const rootElementDarkModeAttributeName = "data-user-color-scheme";

const setLS = (k, v) => {
localStorage.setItem(k, v);
};

const removeLS = (k) => {
localStorage.removeItem(k);
};

const getLS = (k) => {
return localStorage.getItem(k);
};

const getModeFromCSSMediaQuery = () => {
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
};

const resetRootDarkModeAttributeAndLS = () => {
rootElement.removeAttribute(rootElementDarkModeAttributeName);
removeLS(darkModeStorageKey);
};

const validColorModeKeys = {
dark: true,
light: true,
};

const applyCustomDarkModeSettings = (mode) => {
const currentSetting = mode || getLS(darkModeStorageKey);

if (currentSetting === getModeFromCSSMediaQuery()) {
resetRootDarkModeAttributeAndLS();
} else if (validColorModeKeys[currentSetting]) {
rootElement.setAttribute(rootElementDarkModeAttributeName, currentSetting);
} else {
resetRootDarkModeAttributeAndLS();
}
};

const invertDarkModeObj = {
dark: "light",
light: "dark",
};

/**
* get target mode
*/
const toggleCustomDarkMode = () => {
let currentSetting = getLS(darkModeStorageKey);

if (validColorModeKeys[currentSetting]) {
currentSetting = invertDarkModeObj[currentSetting];
} else if (currentSetting === null) {
currentSetting = invertDarkModeObj[getModeFromCSSMediaQuery()];
} else {
return;
}
setLS(darkModeStorageKey, currentSetting);
return currentSetting;
};

/**
* bind click event for toggle button
*/
var btn=$("#wrapper .toggle-mode-btn,#rightmenu-wrapper .toggle-mode-btn");
function bindToggleButton() {
btn.on('click',(e) => {
const mode = toggleCustomDarkMode();
applyCustomDarkModeSettings(mode);
// 添加弹窗
iziToast.info({
timeout: 4000, //调试
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-adjust',
backgroundColor: '#fff',
title: '明暗切换',
message: '已手动切换明暗模式'
});
});
}

applyCustomDarkModeSettings();
document.addEventListener("DOMContentLoaded", bindToggleButton);
volantis.pjax.push(bindToggleButton);
volantis.pjax.send(()=>{
btn.unbind('click');
},'toggle-mode-btn-unbind');

/*添加代码*/
// 自动夜间模式
if (navigator.geolocation) { //获取地理位置 用于判断日出日落时间
navigator.geolocation.getCurrentPosition(
function (position) {
var res = computeSunRiseSunSet(position.coords.latitude, position.coords.longitude, 8);
console.log(res.str)
adjust_time(res.strSunRise, res.strSunSet, "08:00", "12:00", "14:00", "23:00")
},
function (e) {
adjust_time("7:00", "17:30", "08:00", "12:00", "14:00", "23:00") //未允许获取地理位置时,使用默认时间
console.log("未允许获取地理位置,使用默认配置时间")
iziToast.info({
timeout: 6000, //调试
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-times-circle',
backgroundColor: '#fff',
title: '权限获取错误',
message: '未允许获取地理位置<p style="margin-top: 4px;">将使用默认配置时间</p>'
});
throw (e.message);
}
)
}
function adjust_time(beginTime, endTime, morningTime, noonTime, afternoonTime, nightTime) {
const rootElement = document.documentElement;
var strb = beginTime.split(":");
if (strb.length != 2) {
return false;
}

var stre = endTime.split(":");
if (stre.length != 2) {
return false;
}

var strmorning = morningTime.split(":"); //12点
if (stre.length != 2) {
return false;
}

var strnoon = noonTime.split(":"); //12点
if (stre.length != 2) {
return false;
}

var strafternoon = afternoonTime.split(":"); //13点
if (stre.length != 2) {
return false;
}

var strnight = nightTime.split(":"); //23点
if (stre.length != 2) {
return false;
}

var b = new Date();
var e = new Date();
var n = new Date();
var morning = new Date();
var noon = new Date();
var afternoon = new Date();
var night = new Date();

b.setHours(strb[0]);
b.setMinutes(strb[1]);
e.setHours(stre[0]);
e.setMinutes(stre[1]);
morning.setHours(strmorning[0]);
morning.setMinutes(strmorning[1]);
noon.setHours(strnoon[0]);
noon.setMinutes(strnoon[1]);
afternoon.setHours(strafternoon[0]);
afternoon.setMinutes(strafternoon[1]);
night.setHours(strnight[0]);
night.setMinutes(strnight[1]);


$.getJSON("https://v1.hitokoto.cn?max_length=15", function (hitokoto) {
//在这里面处理获得的数据
if (n.getTime() - b.getTime() > 0 && n.getTime() - e.getTime() < 0) {
var daytimetitle = ''
var daytimemessage = ''
if (n.getTime() - morning.getTime() < 0) {
// 早上
daytimetitle = '早安'
}
else if (n.getTime() - noon.getTime() < 0) {
// 上午
daytimetitle = '上午好'
}
else if (n.getTime() - afternoon.getTime() < 0) {
// 中午
daytimetitle = '中午好'
daytimemessage = '<br>要注意休息哦~'
}
else {
// 下午
daytimetitle = '下午好'
}
// 判断是否已经开启夜间模式
if (rootElement.getAttribute('data-user-color-scheme', 'dark')) {
// 已开启夜间模式,修改按钮状态
iziToast.info({
timeout: 4000, //调试
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-sun',
backgroundColor: '#fff',
title: '日间模式切换',
message: daytimetitle + ',已自动为您切换为日间模式'
});
const mode = toggleCustomDarkMode();
applyCustomDarkModeSettings(mode);
}
else {
// 未开启夜间模式,不执行操作
iziToast.info({
timeout: 4000, //调试
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-comment-alt-smile',
backgroundColor: '#fff',
title: daytimetitle + '呀',
message: hitokoto.hitokoto
});
return true;
}
} else {
// 晚上
var nighttitle = ''
var nightmessage = ''
if (night.getTime() - n.getTime() < 0 || n.getTime() - b.getTime() < 0) {
nighttitle = '夜深了'
nightmessage = '<br>该睡觉啦~'
}
else {
nighttitle = '晚上好'
nightmessage = '<br>吃晚饭了吗?要注意眼睛哦。'
}
// 判断是否已经开启夜间模式
if (rootElement.getAttribute('data-user-color-scheme', 'dark')) {
// 已开启夜间模式,不执行操作
iziToast.info({
timeout: 4000, //调试
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fad fa-comment-alt-smile',
backgroundColor: '#fff',
title: nighttitle + '呀',
message: hitokoto.hitokoto
});
return true;
}
else {
// 未开启夜间模式,修改按钮状态
iziToast.info({
timeout: 4000, //调试
icon: 'Fontawesome',
closeOnEscape: 'true',
transitionOut: 'fadeOutRight',
displayMode: 'replace',
layout: '2',
transitionIn: 'bounceInLeft',
position: 'topRight',
icon: 'fas fa-moon',
backgroundColor: '#fff',
title: '夜间模式切换',
message: nighttitle + ',已自动为您切换为夜间模式'
});
const mode = toggleCustomDarkMode();
applyCustomDarkModeSettings(mode);
}
}
});
}
</script>

其他方面

配置项

这里列出一些经常需要的参数

对象 默认值 描述
title / 弹窗的标题
message / 弹窗的消息
timeout 5000 关闭弹窗的时间( 以毫秒为单位 ), false 则常驻
icon / 图标类( 您选择的字体图标, Icomoon, Fontawesome 等 )
layout 1 / 2 弹窗的样式( 单行 / 双行 )
displayMode 0 等待直到弹窗关闭,您才能将其打开( 使用 1
替换已经打开的弹窗( 使用 replace
position bottomRight 默认的弹窗显示位置
bottomRight,bottomLeft,topRight, topLeft,topCenter, bottomCenter,center
transitionIn fadeInUp 默认的弹窗打开动画
bounceInLeft, bounceInRight, bounceInUp, bounceInDown, fadeIn, fadeInDown, fadeInUp, fadeInLeft, fadeInRight, flipInX
transitionOut fadeOut 默认的弹窗关闭动画
fadeOut, fadeOutUp, fadeOutDown, fadeOutLeft, fadeOutRight, flipOutX

弹窗美化

阴影优化

1
2
3
4
5
6
7
.iziToast:after {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important;
border-radius: 8px !important;
}
.iziToast-message.slideIn {
margin-top: 5px !important;
}

夜间模式适配

写入暗黑模式样式中,不可写入主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
.iziToast:after {
border-radius: 8px!important;
}
.iziToast {
background: #333 none repeat scroll 0 0 !important;
}
.iziToast-title.slideIn {
color: #aaa !important;
}
.iziToast-message.slideIn {
color: #aaa !important;
}
.iziToast-icon {
color: #aaa !important;
}
.iziToast > .iziToast-progressbar {
background: rgb(51, 51, 51) !important;
}
.iziToast > .iziToast-progressbar > div {
background: rgb(170, 170, 170) !important;
}
.iziToast > .iziToast-close {
background: url(https://cdn.jsdelivr.net/gh/imsyy/file/pic/close.png) no-repeat 50% 50% !important;
background-size: 8px !important;
}

评论区 请大家友善讨论哦