Anzhiyu主题 一图流渐进式加载 BUG修复

安知鱼主题的一图流渐进式加载返回首页图片显示异常

这个问题主要是因为 Anzhiyu 模板使用了 PJAX(部分页面刷新),而代码目前对 PJAX 的兼容还不完全。


问题所在

当你点击左上角返回首页,页面确实回到了 "/",但因为 PJAX 并不会触发 DOMContentLoaded 或重新执行 <script> 标签内的 JS,所以你原先初始化的 ProgressiveLoad 没有重新运行。

而你虽然监听了 pjax:complete 事件来重新加载图片:

1
2
3
document.addEventListener("pjax:complete", function() {
onPJAXComplete(config);
});

但此事件的绑定是在 onThemeChange() 函数里,而 onThemeChange() 只会在 data-theme 改变时触发。

❗所以点击左上角时 PJAX 发生了,但因为 data-theme 没变,导致 onThemeChange() 没有运行,从而 pjax:complete 也没有监听。


解决方案

修改方式:

你需要把监听 pjax:complete 的部分挪到全局作用域,而不是只在 onThemeChange() 中绑定一次。修改如下:

修改内容:

1
2
3
4
5
6
//  放在 IIFE 立即执行函数内部最底部,加上全局 PJAX 监听
document.addEventListener("pjax:complete", function() {
const currentTheme = getCurrentTheme();
const config = ldconfig[currentTheme];
initProgressiveLoad(config);
});

原来的代码中:

1
2
3
document.addEventListener("pjax:complete", function() {
onPJAXComplete(config);
});

这段放在 onThemeChange 内部,所以页面未更换主题时,不会注册 pjax:complete,导致首页跳转无效。


完整修复后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
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
/**
* @description 实现 medium 的渐进加载背景的效果(支持 PJAX 与主题切换)
* 2025/05/20 修复:By 北之歌
*/
(function () {
class ProgressiveLoad {
constructor(smallSrc, largeSrc) {
this.smallSrc = smallSrc;
this.largeSrc = largeSrc;
this.initTpl();
this.container.addEventListener(
"animationend",
() => {
this.smallStage.style.display = "none";
},
{ once: true }
);
}

initTpl() {
this.container = document.createElement("div");
this.smallStage = document.createElement("div");
this.largeStage = document.createElement("div");
this.smallImg = new Image();
this.largeImg = new Image();
this.container.className = "pl-container";
this.smallStage.className = "pl-img pl-blur";
this.largeStage.className = "pl-img";
this.container.appendChild(this.smallStage);
this.container.appendChild(this.largeStage);
this.smallImg.onload = this._onSmallLoaded.bind(this);
this.largeImg.onload = this._onLargeLoaded.bind(this);
}

progressiveLoad() {
this.smallImg.src = this.smallSrc;
this.largeImg.src = this.largeSrc;
}

_onLargeLoaded() {
this.largeStage.classList.add("pl-visible");
this.largeStage.style.backgroundImage = `url('${this.largeSrc}')`;
}

_onSmallLoaded() {
this.smallStage.classList.add("pl-visible");
this.smallStage.style.backgroundImage = `url('${this.smallSrc}')`;
}
}

const executeLoad = (config, target) => {
console.log("执行渐进背景替换");
const isMobile = window.matchMedia("(max-width: 767px)").matches;
const loader = new ProgressiveLoad(
isMobile ? config.mobileSmallSrc : config.smallSrc,
isMobile ? config.mobileLargeSrc : config.largeSrc
);
if (target.children[0]) {
target.insertBefore(loader.container, target.children[0]);
} else {
target.appendChild(loader.container);
}
loader.progressiveLoad();
};

const ldconfig = {
light: {
smallSrc: "https://static.xihuannio.cn/static-resources/images/web/web.png",
largeSrc: "https://static.xihuannio.cn/static-resources/images/web/web.png",
mobileSmallSrc:
"https://static.xihuannio.cn/static-resources/images/web/08f083a0b3b26ac388a0c7ecb35478abbff557fa.jpg",
mobileLargeSrc:
"https://static.xihuannio.cn/static-resources/images/web/08f083a0b3b26ac388a0c7ecb35478abbff557fa.jpg",
enableRoutes: ["/"],
},
dark: {
smallSrc: "https://static.xihuannio.cn/static-resources/images/web/web.png",
largeSrc: "https://static.xihuannio.cn/static-resources/images/web/web.png",
mobileSmallSrc:
"https://static.xihuannio.cn/static-resources/images/web/08f083a0b3b26ac388a0c7ecb35478abbff557fa.jpg",
mobileLargeSrc:
"https://static.xihuannio.cn/static-resources/images/web/08f083a0b3b26ac388a0c7ecb35478abbff557fa.jpg",
enableRoutes: ["/"],
},
};

const getCurrentTheme = () => {
return document.documentElement.getAttribute("data-theme");
};

function initProgressiveLoad(config) {
const container = document.querySelector(".pl-container");
if (container) {
container.remove();
}
const target = document.getElementById("page-header");
if (target && target.classList.contains("full_page")) {
executeLoad(config, target);
}
}

// 初始加载
const initTheme = getCurrentTheme();
const initConfig = ldconfig[initTheme];
initProgressiveLoad(initConfig);

// 监听主题切换
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (
mutation.attributeName === "data-theme" &&
location.pathname === "/"
) {
const currentTheme = getCurrentTheme();
const config = ldconfig[currentTheme];
initProgressiveLoad(config);
}
});
});

observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});

document.addEventListener("pjax:complete", function () {
const currentTheme = getCurrentTheme();
const config = ldconfig[currentTheme];
initProgressiveLoad(config);
});
})();