fix(front): 修复无限滚动只加载一批就卡在"加载中..."的问题
2 个文件变更
+41
-11
fangqihang1717@163.com
| •web/static/app.css | +1 -0 |
| •web/static/app.js | +40 -11 |
变更内容
diff --git a/web/static/app.css b/web/static/app.css
index 1652474..6d9eead 100644
--- a/web/static/app.css
+++ b/web/static/app.css
@@ -178,6 +178,7 @@ button { font-family: inherit; }
.view-all:hover { color: var(--clv-accent); }
.load-state { text-align: center; color: var(--clv-muted); font-size: 13px; padding: 16px 0; }
+.load-state:empty { padding: 0; }
.sentinel { height: 1px; }
/* 悬浮发帖按钮 */
diff --git a/web/static/app.js b/web/static/app.js
index 867d5a3..da78477 100644
--- a/web/static/app.js
+++ b/web/static/app.js
@@ -207,11 +207,39 @@
var sentinel = document.getElementById('sentinel');
var topic = box.dataset.topic || '';
var last = 0, loading = false, done = false;
+ var io = null;
+ var PAGE = 10;
+
+ // 页面底部是否已进入预加载范围
+ function nearBottom() {
+ return window.innerHeight + window.scrollY > document.body.offsetHeight - 500;
+ }
+
+ // 重新观察哨兵。observe() 会立即按"当前"相交状态回调一次,而这正是关键:
+ // IntersectionObserver 只在相交状态**变化**时回调,若一批数据插入后哨兵仍在
+ // 预加载范围内,状态没变就不会再回调,页面就会永远卡在"加载中..."。
+ // 内容不足以填满屏幕时(话题栏收起后页面变短尤其明显),还要靠它续加载。
+ function kick() {
+ if (io && sentinel && sentinel.parentNode) {
+ io.unobserve(sentinel);
+ io.observe(sentinel);
+ } else if (!io && nearBottom()) {
+ load();
+ }
+ }
+
+ function finish(msg) {
+ done = true;
+ state.textContent = msg;
+ if (sentinel) sentinel.remove();
+ if (io) { io.disconnect(); io = null; }
+ }
function load() {
if (loading || done) return;
loading = true;
- api('/api/v1/posts?before=' + last + '&limit=10&topic=' + encodeURIComponent(topic))
+ state.textContent = '加载中...';
+ api('/api/v1/posts?before=' + last + '&limit=' + PAGE + '&topic=' + encodeURIComponent(topic))
.then(function (r) {
loading = false;
if (!r || !r.ok) {
@@ -221,11 +249,13 @@
var posts = r.posts || [];
posts.forEach(function (p) { box.appendChild(cardEl(p)); });
if (posts.length) last = posts[posts.length - 1].id;
- if (posts.length < 10) {
- done = true;
- state.textContent = last ? '已经到底啦' : '还没有帖子,点击右下角发布第一条';
- if (sentinel) sentinel.remove();
+ if (posts.length < PAGE) {
+ finish(last ? '已经到底啦' : '还没有帖子,点击右下角发布第一条');
+ return;
}
+ // 还有更多:清掉加载提示,并让哨兵重新判断是否需要立即续加载
+ state.textContent = '';
+ kick();
})
.catch(function () {
loading = false;
@@ -234,14 +264,13 @@
}
if (sentinel && 'IntersectionObserver' in window) {
- new IntersectionObserver(function (entries) {
+ io = new IntersectionObserver(function (entries) {
if (entries[0].isIntersecting) load();
- }, { rootMargin: '400px' }).observe(sentinel);
+ }, { rootMargin: '400px' });
+ io.observe(sentinel);
} else {
- // 兜底:滚动监听
- window.addEventListener('scroll', function () {
- if (window.innerHeight + window.scrollY > document.body.offsetHeight - 500) load();
- });
+ // 兜底:滚动监听(首屏内容不足时同样需要主动续加载)
+ window.addEventListener('scroll', function () { if (nearBottom()) load(); });
}
load();
}