PC上拉滚动优化

🔥 上拉加载:从底层原理到实战技巧(Vue/React全场景)

背景 上拉加载作为提升用户体验的「隐形神器」,在聊天界面、商品列表、动态流等场景中无处不在。本文将手把手带你掌握三种主流实现方案,从底层原理到实战技巧一网打尽!

方法一:观察者模式 -- 优雅的现代方案

利用 IntersectionObserver API 实现轻量级上拉加载,完美适配 Vue/React 等框架。

核心代码

vue{4-25} 复制代码
<template>
    <div class="list-container">
        <div v-for="item in list" :key="item.id">{{ item }}</div>
        <!-- 触发器:关键在最后一位 -->
        <div id="bottom-trigger" class="trigger"></div>
    </div>
</template>
<script>
export default {
    mounted() {
       const bottomTrigger = document.getElementById('bottom-trigger');
        // 创建一个 IntersectionObserver 实例
        const observer = new IntersectionObserver(
            (entries, observer) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        // 当触底检测元素进入视口时
                        console.log('Bottom reached!');
                        // do something 加载更多数据
                        this.loadMore()
                    }
                });
            },
            {
                // 配置观察选项
                threshold: 0.5 // 当触底检测元素至少 50% 进入视口时触发
            }
        );
        // 开始观察触底检测元素
        observer.observe(bottomTrigger);
    },
    methods: {
        async loadMore() {
            // 模拟异步加载
            const newData = await fetchData();
            this.list.push(...newData);
        }
    }
}
</script>   

💡 关键技巧

  1. 触发器定位:必须放在列表最后一位,确保滚动到底部时触发
  2. 性能优化 :设置 threshold 控制触发灵敏度(0.1=10%进入视口)
  3. 防抖机制 :通过 IntersectionObserver 内置防抖,无需额外处理

方法二:Element UI InfiniteScroll -- 企业级方案

Element UI 的 v-infinite-scroll 指令封装了复杂逻辑,适合快速开发。

📌相关api

  • v-infinite-scroll:赋值相应的加载方法,可实现滚动到底部时自动执行加载方法
  • infinite-scroll-distance:触发加载的距离阈值,单位为px;可以根据开发实际情况调整

📌 核心代码

vue 复制代码
<template>
    <div 
      v-infinite-scroll="load" 
      :infinite-scroll-disabled="loading || !hasMore" 
      :infinite-scroll-distance="50"
      style="height: 600px; overflow: auto;"
    >
        <div v-for="item in list" :key="item.id" class="list-item">
            {{ item.content }}
        </div>
        <div v-if="loading" class="loading">正在加载...</div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            list: [],
            loading: false,
            hasMore: true
        };
    },
    methods: {
        async load() {
            if (this.loading) return; // 防止重复加载
            this.loading = true;
            try {
                const res = await fetchData();
                this.list.push(...res);
                this.hasMore = res.length > 0;
            } finally {
                this.loading = false;
            }
        }
    }
};
</script>

🔍 源码解析彩蛋

在 Element UI 的 getScrollParent 方法中:

js 复制代码
if (['scroll', 'auto'].includes(overflow) || ['scroll', 'auto'].includes(overflowY)) { 
return parent; 
}
  • 原理 :通过检查 overflow 属性判断滚动容器
  • 注意 :若父容器 overflow: visible,会退化到全局滚动(window)
  • 解决方案 :强制设置容器 overflow: auto

方法三:React实战 -- react-infinite-scroll-component

React社区的 react-infinite-scroll-component 提供了更灵活的配置。本项目使用版本为:"react-infinite-scroll-component": "6.1.0"

🚀 核心代码

jsx 复制代码
import InfiniteScroll from 'react-infinite-scroll-component'
import { Empty } from 'antd'

const MyList = () => {
  const [list, setList] = useState([])
  const [hasMore, setHasMore] = useState(true)
  const loadingRef = useRef(false); // 标记是否在加载中

  
  const fetchData = async () => {
    if (loadingRef.current) return; // 如果正在加载,直接返回
    loadingRef.current = true;
    try{
      const res = await fetch('/api/data')
      const data = await res.json()
      setList((prev) => [...prev, ...data])
      setHasMore(data.length > 0)
    } finally {
      loadingRef.current = false; // 无论成功失败,重置状态
    }
   
  }
 
  return (
    <InfiniteScroll
      dataLength={list.length}
      next={fetchData}
      hasMore={hasMore}
      loader={<h4>正在加载...</h4>}
      endMessage={<p>没有更多数据啦~</p>}
      height={window.innerHeight - 100} // 自适应高度
    >
      {list?.length ? list.map((item) => (
        <div
          key={item.id}
          className="list-item"
        >
          {item.content}
        </div>
      )) : <Empty className="empty" />
      }
    </InfiniteScroll>
  )
}

📌相关api

  • dataLength: 已加载的数据条数,用于判断是否需要加载更多数据,这里用页码乘以每页条数计算
  • next: 当滚动到底部时会触发这个函数
  • hasMore: true表示还可以加载更多,false表示已经加载完所有数据
  • loader: 加载中时显示的内容
  • endMessage: 如果没有数据则显示"没有更多了",否则不显示任何内容
  • height: 固定高度可以创建一个独立的滚动区域, 赋值数字即可

💡 高阶技巧

  1. 动态高度 :通过 height={window.innerHeight - 100} 实现自适应
  2. 防抖优化 :配合 useRef 缓存请求,避免高频滚动时重复触发
  3. 错误处理 :添加 errorBoundary 组件处理加载异常

📌 总结对比表

方法 适用场景 优势 劣势
IntersectionObserver 现代浏览器项目 轻量、标准API 需手动处理边界条件
Element UI 企业级Vue项目 零配置快速集成 需注意容器样式限制
react-infinite-scroll React生态项目 配置灵活 需处理组件生命周期

选择方案时优先考虑:

  1. 浏览器兼容性要求
  2. 项目技术栈特性
  3. 数据量级(超大数据建议结合虚拟滚动)

🌟 本文代码已通过 Vue2/React18 测试,实战中记得添加 loading 状态和错误提示!

相关推荐
用户37203749260181 分钟前
把 10MB 中文语义模型塞进浏览器:STSB 做到教师模型的 93%,但线上 top1 只有 42%
前端
光锥智能11 分钟前
海康机器人举行2026移动机器人新品发布会:箱式存拣升级,「明智」系列发布
java·前端·机器人
计算机魔术师12 分钟前
Anthropic 上市文件最吓人的一幕,不是亏损 807 亿
前端
alsmile23 分钟前
AI友好的可视化图形引擎自我革命:Meta2d.js 2.0 历时一年全新重写,性能与多人协作全面升级
前端·开源·数据可视化
行思理24 分钟前
Nginx 跨站请求(CORS)配置完全指南:从原理到生产实践
java·前端·nginx
粥里有勺糖44 分钟前
视野修炼-技术周刊第137期 | 编程已经面目全非
前端·github·ai编程
IT_陈寒1 小时前
Python的列表推导式用不好真的会爆内存你知道吗
前端·人工智能·后端
moshuying1 小时前
块扩散 + GDN 改造:Clover 把「并行生成」塞进了 Agent 的长上下文里
前端·算法
kyriewen1 小时前
我算了笔账:AI 编程工具一年烧掉两台 MacBook
前端·人工智能·程序员
moshuying2 小时前
扩散模型开始写代码、开网页了:350 亿参数,速度比 Jev 快一倍
前端·算法