Hexo Fluid 背景图随日夜模式切换

前情提要

1. 获取当前模式

要解决的第一件事是获取当前页面采用的模式。

按F12打开控制台,很容易发现

1
2
3
4
<a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
<i class="iconfont icon-dark" id="color-toggle-icon" data="light">
</i>
</a>

其中:

  • class="iconfont icon-dark"指的是当前显示的按钮图标,当鼠标悬停在上方时就会发生改变,所以我们需要的不是这个
  • id="color-toggle-icon"可以通过唯一id获取这个对象
  • data="light"记录的是当前所在的模式,正是我们需要的

因此,要获取当前的模式,只需要在自定义js文件backgroundize.js中写入以下代码

1
2
3
4
5
6
document.querySelector('#color-toggle-btn').addEventListener(
"click", () => {
const dataValue = document.getElementById('color-toggle-icon').getAttribute('data'); // 获取data属性
console.log('data属性值是:', dataValue);
}
)

打开控制台看看效果:

发现获取的data值和当前页面的实际模式刚好相反,这个问题不大,比较烦人的是每一次点击按钮控制台都会打印出两个完全相同的值。通过检查按钮的属性,发现这个click事件被重复绑定两次。

解决方法:定义一个全局变量作为标记,初始值为undefined,绑定一次之后赋值为true,因此以后不会重复绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 监听主题切换按钮点击事件
function getCurrentMode() {
return document.getElementById('color-toggle-icon').getAttribute('data');
}

// 检查是否已初始化
if (!window._colorToggleInitialized) {
function handleColorToggle() {
console.log(getCurrentMode());
}

document.querySelector('#color-toggle-btn').addEventListener("click", handleColorToggle);
window._colorToggleInitialized = true; // 标记为已初始化
}

修改后的效果:

backgroundize.js只被绑定一次

可以看出非用户自定义的文件也有被重复绑定的情况,原因暂时不太清楚。

2. 替换背景图

文章页的背景图:

1
<div id="web_bg" style="background-image: url(&quot;/img/girl.webp&quot;);position: fixed;width: 100%;height: 100%;z-index: -1;background-size: cover;"></div>

首页的背景图:

1
<div id="web_bg" style="background-image: url(&quot;/img/miku.webp&quot;);position: fixed;width: 100%;height: 100%;z-index: -1;background-size: cover;"></div>

注意仅从html上已经无法区分这两张图片,而我的目标是只在文章页的时候启用切换。注意到文章页和首页的<head>标签

1
2
<meta property="og:type" content="article">
<meta property="og:type" content="website">

所以可以从这里下手进行区分。完整的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
// 检查是否已初始化
if (!window._colorToggleInitialized) {

//为点击事件绑定切换背景的功能
document.querySelector('#color-toggle-btn').addEventListener("click", setBackgroundImage);

window._colorToggleInitialized = true; // 标记为已初始化
}


/**
* 获取当前日/夜模式
* @returns light:夜,dark:日(刚好反过来)
*/
function getCurrentMode() {
return document.getElementById('color-toggle-icon').getAttribute('data');
}

/**
* 设置背景图片
* 通过Open Graph meta判断当前页面是不是文章页
* 如果是,则根据当前的模式替换背景图片
*/
function setBackgroundImage() {

const ogTypeMeta = document.querySelector('meta[property="og:type"]');
const isPost = ogTypeMeta && ogTypeMeta.content === 'article';

if (isPost) {
const bgDiv = document.getElementById('web_bg');

if (bgDiv) {

if (getCurrentMode() === 'light') bgDiv.style.backgroundImage = 'url("/img/night.webp")';

else bgDiv.style.backgroundImage = 'url("/img/girl.webp")';

//console.log("成功替换");
}
}

}

/**
* 上面的代码只有当点击日夜切换按钮时才生效。
* 如果在首页就切换为黑夜模式,进入文章页后会发现背景仍然是白色的
* 所以这里利用DOMContentLoaded事件,每当一个页面的HTML结构加载完成时判断是否是文章页,是的话就根据模式替换背景
*/
document.addEventListener('DOMContentLoaded', function () {
// 通过 Open Graph 协议判断
const ogTypeMeta = document.querySelector('meta[property="og:type"]');
const isPost = ogTypeMeta && ogTypeMeta.content === 'article';

if (isPost) { // 判断进入文章页

const bgDiv = document.getElementById('web_bg');

if (bgDiv) {

if (getCurrentMode() === 'light') bgDiv.style.backgroundImage = 'url("/img/night.webp")';

else bgDiv.style.backgroundImage = 'url("/img/girl.webp")';

//console.log("成功替换");
}
}
});

然后再加入css代码

1
2
3
4
5
6
7
8
9
10
11
/* 明暗切换 */
#web_bg {
transition: background-image 0.5s ease-in-out !important;
}

/* 由黑夜切换为白天的时间会长一点 */
@media (prefers-color-scheme: dark) {
#web_bg {
transition-duration: 0.8s !important;
}
}

因为这里采用的逻辑是只有检测到加载的页面是文章页时才执行北京替换的逻辑,所以使用了两处替换背景的功能:初次加载页面时、按下日夜切换按钮时。

遗留问题

上面的实现方式有一个缺陷:刚进入文章页时有概率先显示出config.fluid.yml中配置的原背景图,再渐变转换成预期的背景图,看起来比较突兀。因为我之前配置过预加载功能,所以干脆直接把原背景图换成和加载页面相同底色的图了。

另外,在文章页内第一次点击日夜切换按钮时,因为背景图只有在需要它的时候才会开始加载,所以第一次背景会闪烁一下然后突然出现背景图,后续再次切换模式的时候才会正常。要解决这个问题就要使用预加载,提前加载背景图片,不过我目前并不清楚预加载的具体实现方式,所以暂时就先这样了。


Hexo Fluid 背景图随日夜模式切换
http://example.com/2025/04/26/白天黑夜背景图切换/
作者
banyee
发布于
2025年4月26日
许可协议