Nuxt 2 无限滚动重复触发请求:如何解决数据重复渲染问题
解决Nuxt 2无限滚动中请求重复触发的问题
这个问题的核心是没有利用loading状态阻止重复请求,再加上Vue响应式更新带来的页面重排可能再次触发scroll事件,最终导致getContents被调用两次。下面是修复后的完整代码:
<template> <main> <div v-for="content in contents" :key="content.id"> <div>{{ content.name }}</div> <!-- 修复了模板插值语法的错误 --> </div> <!-- 新增加载状态提示,提升用户体验 --> <div v-if="loading" class="loading">加载中...</div> </main> </template> <script> import { throttle } from 'lodash' import axios from 'axios' export default { data() { return { loading: false, contents: [] } }, methods: { handleScroll() { const pixelsFromWindowBottomToBottom = document.body.offsetHeight - window.pageYOffset - window.innerHeight // 关键:只有不在加载状态时,才触发请求 if (pixelsFromWindowBottomToBottom < 200 && !this.loading) { this.getContents() } }, async getContents() { this.loading = true try { const { data } = await axios.get('foo') this.contents = this.contents.concat(data) } catch (err) { // 处理请求失败的情况,比如给用户提示 console.error('加载内容失败:', err) } finally { // 无论请求成功/失败,都重置loading状态 this.loading = false } } }, created() { if (process.browser) { // 绑定节流后的滚动事件 document.addEventListener('scroll', throttle(this.handleScroll, 300)) } }, beforeDestroy() { // 组件销毁时移除事件监听,避免内存泄漏 if (process.browser) { document.removeEventListener('scroll', throttle(this.handleScroll, 300)) } } } </script>
为什么原来的代码会触发两次请求?
你提到问题源于this.loading = true,本质原因是:
- 第一次滚动到触发位置时,调用
getContents并设置loading = true,这会触发Vue的响应式更新,导致页面重排。 - 页面重排可能改变页面高度或滚动位置,而你的scroll事件仅用300ms节流限制,如果重排发生在节流时间窗口内,会再次触发
handleScroll;此时因为没有判断loading状态,就会再次调用getContents,发起第二次请求。
额外优化说明:
- 将
getContents改成async/await写法,比Promise链更易读维护。 - 新增
beforeDestroy钩子移除scroll事件监听,防止组件销毁后事件残留导致内存泄漏。 - 修复了模板中插值语法的错误(原代码写成了
{content.name},正确应为{{ content.name }})。 - 增加了加载状态提示,让用户清晰感知加载过程。
内容的提问来源于stack exchange,提问作者Sylar
相关产品推荐
相关产品推荐

