滚动加载时取消旧请求的核心是新请求发起前中止上一次未完成的请求;需用abortcontroller管理,单区域共用一个实例,多区域按key隔离,配合loading状态防重复触发。

滚动加载时取消旧请求,核心是“新请求发起前,中止上一次未完成的请求”。这和搜索框防抖取消逻辑一致,但触发时机从输入变化变成了滚动到底部。关键不在滚动本身,而在每次发起加载请求前,确保前一个同类型请求已退出。
用 AbortController 管理单个滚动请求
适用于页面只有一个滚动加载区域(如商品列表、文章流)的场景。在组件内维护一个 abortController 引用,每次触发加载前先 abort,再新建:
- 监听滚动事件或使用
IntersectionObserver检测底部元素是否进入视口 - 加载函数开头判断:若已有 controller,调用
.abort() - 创建新
AbortController,把.signal传给 axios 或 fetch - 组件卸载时(
onBeforeUnmount)统一 abort,避免内存泄漏
多个滚动区域共存时按标识隔离
如果一个页面有多个独立滚动区(如“推荐”“热门”“最新”三个 tab 下的列表),不能共用一个 controller,否则切 tab 会误杀其他区的请求。需要为每个区域分配唯一 key:
- 用 Map 存储:
const pendingControllers = new Map<string abortcontroller>()</string> - 加载时以 tabId 或 API 路径为 key,先取旧 controller 并 abort,再存入新的
- 例如:
pendingControllers.get('hot')?.abort(); pendingControllers.set('hot', new AbortController()) - 切换 tab 或离开页面时,可批量清理对应 key 的 controller
配合 loading 状态避免重复触发
光取消请求还不够——用户快速滚动可能连续触发多次“到底部”,导致短时间内反复新建 controller 和发请求。建议加一层保护:
- 用
ref<boolean></boolean>控制加载中状态(如isLoading.value = true) - 滚动检测回调里先判断
if (isLoading.value || hasMore.value === false) return - 成功加载后更新
hasMore(后端返回是否还有下一页)并重置isLoading - 失败时也需重置
isLoading,否则后续滚动将被阻塞
不依赖第三方库的轻量实现示例
无需封装 hook,几行代码就能跑通:
<script setup><br>import { ref, onBeforeUnmount } from '<a style="color:#f60; text-decoration:underline;" title= "vue"href="https://m.php.cn/zt/15721.html" target="_blank">vue'<br>import axios from 'axios'<br><br>const isLoading = ref(false)<br>const list = ref([])<br>const hasMore = ref(true)<br>const abortController = ref<AbortController | null>(null)<br><br>const loadMore = async () => {<br> if (isLoading.value || !hasMore.value) return<br> isLoading.value = true<br><br> // 取消上一次<br> if (abortController.value) abortController.value.abort()<br> abortController.value = new AbortController()<br><br> try {<br> const res = await axios.get('/api/items', {<br> params: { offset: list.value.length },<br> signal: abortController.value.signal<br> })<br> list.value.push(...res.data.items)<br> hasMore.value = res.data.has_more<br> } catch (err) {<br> if (axios.isCancel(err)) {<br> // 忽略取消错误<br> } else {<br> console.error(err)<br> }<br> } finally {<br> isLoading.value = false<br> }<br>}<br><br>onBeforeUnmount(() => {<br> if (abortController.value) abortController.value.abort()<br>})<br></script>
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











