记一次使用PWA(ServiceWorker)后懒加载失效解决

问题解决

2022-03-09
由于 文章时效性提示 会导致懒加载和其他插件异常(因为用了 innerHTML)。改为

1
2
3
posts[0].insertAdjacentHTML('afterbegin', '<div class="note note-warning" style="font-size:0.9rem"><p>' +
'<div class="h6">文章时效性提示</div><p>这是一篇发布于 ' + days + ' 天前的文章,部分信息可能已发生改变,请注意甄别。' +
'</p></p></div>');

后正常

问题所在

不知道是哪方的 BUG,首次加载和 http/s 下加载都正常。

而在 ServiceWorker 下, IntersectionObserver.entries.isIntersecting 返回都是 false,导致评论框和 lazyload 图片不显示。

导致问题的原因是 PWA 加载太快,导致 DOM 还没渲染完成就执行了io.observe(document.getElementById(targetId));
并且由于没有获取到元素信息(entries[0].intersectionRect为空),所以就不会有元素可视的回调。
解决方案就是增加失败后 Rollback 到 scroll 模式判断是否可见。详见下面的代码。

函数位置

/source/js/utils.js
waitElementVisible

1
2
3
4
5
6
7
8
9
10
var io = new IntersectionObserver(function(entries, ob) {
if (entries[0].isIntersecting) { //在service worker下,返回的都是false
callback && callback();
ob.disconnect();
}
}, {
threshold : [0],
rootMargin: (window.innerHeight || document.documentElement.clientHeight) + 'px'
});
io.observe(document.getElementById(targetId));

解决方法/思路

评论换成 js 判断加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  if (!isBot && runningOnBrowser){// && supportsIntersectionObserver) {

if('attachEvent' in window)document.attachEvent("scroll", _callback);
if('addEventListener' in window)document.addEventListener('scroll', _callback);
function _callback() {
const _target = document.getElementById(targetId);
//滚动条高度+视窗高度 = 可见区域底部高度
let visibleBottom = window.scrollY + document.documentElement.clientHeight;
//可见区域顶部高度
let visibleTop = window.scrollY;
let centerY = _target.offsetTop + (_target.offsetHeight / 2);
if (centerY > visibleTop && centerY < visibleBottom) {
if('attachEvent' in window)document.detachEvent('scroll', _callback);
if('addEventListener' in window)document.removeEventListener('scroll', _callback);
callback && callback();
}
}

新的方法

更新 2021 年 03 月 17 日 19 点 10 分

直接重写整个waitElementVisible函数,正常的情况下使用IntersectionObserver,失败的情况下回退到使用scroll

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
waitElementVisible: function(targetId, callback) {
var runningOnBrowser = typeof window !== 'undefined';
var isBot = (runningOnBrowser && !('onscroll' in window)) || (typeof navigator !== 'undefined'
&& /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent));
var supportsIntersectionObserver = 'IntersectionObserver' in window;
var attachEvent = 'attachEvent' in window;
var addEventListener = 'addEventListener' in window;
if (!isBot && runningOnBrowser && (attachEvent || addEventListener)) {
var _scroll = function() {
var _callback = function() {
var _target = document.getElementById(targetId);
//滚动条高度+视窗高度 = 可见区域底部高度
var visibleBottom = window.scrollY + document.documentElement.clientHeight;
//可见区域顶部高度
var visibleTop = window.scrollY;
var centerY = _target.offsetTop + (_target.offsetHeight / 2);
if (centerY > visibleTop && centerY < visibleBottom) {
if (attachEvent)document.detachEvent('scroll', _callback);
if (addEventListener)document.removeEventListener('scroll', _callback);
callback && callback();
}
};
if (attachEvent)document.attachEvent('scroll', _callback);
if (addEventListener)document.addEventListener('scroll', _callback);
};
if (supportsIntersectionObserver) {
var io = new IntersectionObserver(function(entries, ob) {
//如果失败,回退到scroll方式
if (entries[0].intersectionRect.x <= 0) { _scroll(); ob.disconnect(); return; }
if (entries[0].isIntersecting) {
callback && callback();
ob.disconnect();
}
}, {
threshold : [0],
rootMargin: (window.innerHeight || document.documentElement.clientHeight) + 'px'
});
io.observe(document.getElementById(targetId));
} else {
_scroll();
}
} else {
callback && callback();
}
},

图片加载我直接换了一个库

使用了lazyloadjs.cn的 js 加载

scripts/events/lib/lazyload.js第 32-35 行改为

1
2
3
4
5
if (/data-src=/i.test(str)) {
return str;
}
return str.replace(p1, `${loadingImage}" class="lazyload" data-src="${p1}`);

如果开启了 progressbar,相应的/source/js/plugins.js

var images = $('main img:not([srcset])');

也要修改为

var images = $('main img:not([data-src])');


至此修改完成.
题外话。提交了 pr 到 fluid-dev,结果失败,出现了 50 多个错误,看了一下,竟然全都是语法错误,惭愧惭愧


记一次使用PWA(ServiceWorker)后懒加载失效解决
https://cuojue.org/read/fix-hexo-fluid-theme-comments-and-images.html
作者
WeiCN
发布于
2021年3月7日
更新于
2021年3月7日
许可协议