后端必须返回items、has_more、next_offset三个字段;前端须用insertadjacenthtml('beforeend', ...)追加内容,禁用按钮防连点,并统一管理loading与错误状态。

手动加载更多按钮不是加个 click 事件就能跑通的,核心卡点在「状态不一致」和「DOM 插入方式错误」——90% 的线上 bug 都出在这两处。
后端 JSON 必须返回哪些字段?
别让前端自己猜分页边界。接口至少得稳定返回三个字段:
-
items:本次要插入的数组,每项结构必须和首屏完全一致(比如都有id、title、content) -
has_more:布尔值,决定按钮是否继续显示;不能只看items.length === 0,否则接口报错返回空数组会被误判为“已到底” -
next_offset或next_cursor:下一次请求用的参数;禁止前端靠offset + 10硬算,否则跳页、重复拉取、ID 乱序全来了
绝对不要返回 html 字段或带标签的字符串——这是 XSS 风险口,也破坏语义和 SEO。
insertAdjacentHTML('beforeend', ...) 为什么不能用 innerHTML +=?
innerHTML += 表面省事,实则危险:
- 它会强制浏览器重新解析整个容器 HTML,已绑定的事件监听器全部丢失
- 输入框焦点、滚动位置、动态状态(如 checkbox 选中态)全被重置
- 列表会明显“闪一下”,用户感知差
正确做法是只把新内容塞到末尾,不动旧 DOM:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 如果后端返回 HTML 字符串:
container.insertAdjacentHTML('beforeend', htmlString) - 如果返回纯 JSON:
items.map(item => `<div class="item" data-id="${item.id}">${item.title}</div>`).join('')拼好再插 - 确保容器有明确
id或class,别用document.querySelector('button')这类模糊选择器找错父容器
按钮点击没反应或连点崩溃?先查这三件事
90% 的“点不动”问题都卡在这几个地方:
- 按钮是
<button></button>但没写type="button",又恰巧在<form></form>里——点击直接触发表单提交。要么加type="button",要么回调里写event.preventDefault() - 没做防连点:点击后不立刻设
button.disabled = true,用户手快点两次,两个请求并发,后返回的覆盖先返回的,列表顺序错乱 - 没处理
loading状态:按钮点击后没加is-loading类,用户看不到反馈,以为卡死,又猛点
更稳妥的做法是加 loading 标记:let isLoading = false,点击前先判断,请求结束再置为 false;别只依赖 DOM 按钮状态——用户可能用键盘触发、或绕过 UI 直接调函数。
fetch 请求乱序覆盖怎么办?
用户快速点两次,“加载更多”按钮发出两个请求,后发的先返回,把先发的数据冲掉了。这不是 UI 问题,是请求生命周期没管住:
- 最简方案:每次发请求前,先调
abortController.abort()(需在fetch里传signal) - 次选方案:给每次请求打唯一标记
requestId = Date.now(),成功回调里先比对if (requestId !== latestRequestId) return - 最基础但有效的兜底:点击后禁用按钮,响应完成再恢复,并配合 CSS 显示“加载中…”文字或骨架
真正难的不是写加载逻辑,而是让“加载中”“加载失败”“已到底”这三种状态,在各种网络波动、后端异常、用户乱点的情况下,始终准确反映真实数据边界。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










