滚动加载原理和应用

341 阅读4分钟

技术原理

原理讲解

rolling_loading_principle.png

上面的图片就是上划滚动或者左划滚动时每一个距离的描述,当上划滚动或者左划滚动时,滚动距离不断增加,剩余距离不断减少,可视区域高度或者宽度一直不变,当剩余距离小于一个指定距离时就发出请求加载数据。

代码实现

使用伪代码实现上划滚动加载上述过程:

// 获取可视区域高度
const screenHeight = container?.offsetHeight;
// 获取内容总高度
const elementHeight = element?.offsetHeight;
// 设置指定高度,当剩余距离小于指定高度加载数据
const targetHeight = 100;

const onScrollEvent = () => {
  // 获取元素的滚动距离(垂直方向)
  const scrollDistance = element.scrollTop;
  // 获取剩余距离
  const remainingDistance = elementHeight - screenHeight - scrollDistance;

  if (remainingDistance < targetHeight) {
    // 请求数据
  }
};

container.addEventListener('scroll', onScrollEvent);

使用伪代码实现左划滚动加载上述过程:

// 获取可视区域宽度
const screenWidth = container?.offsetWidth;
// 获取内容总宽度
const elementWidth = element?.offsetWidth;
// 设置指定宽度,当剩余距离小于指定宽度加载数据
const targetWidth = 100;

const onScrollEvent = () => {
  // 获取元素的滚动距离(水平方向)
  const scrollDistance = element.scrollLeft;
  // 获取剩余距离
  const remainingDistance = elementWidth - screenWidth - scrollDistance;

  if (remainingDistance < targetWidth) {
    // 请求数据
  }
};

container.addEventListener('scroll', onScrollEvent);

注意:要实现上述的滚动加载,有几个前提条件,首先需要设置可视区域的高度或者宽度,且可视区域不能禁止滚动,其次内容区域高度/宽度要大于可视区域高度/宽度,最后滚动的事件最好加上防抖处理,否则触发的频次太高。

应用场景

实现一个下划滚动加载

移动端常见的购物网站或者文章网站的列表页面,当用户上划时,列表就会自动加载,甚至有些文章网站还可以实现自动滚动加载,不需要用户不断的滑动,下面简单实现一下功能:

点击查看代码 点击查看效果

实现一个左划滚动加载

左划和上划的原理相似,但是实现上有以下区别:

  1. 滚动容器要设置宽度和横向滚动等样式

    .left-rolling-loading {
       width: 750px;
       overflow-x: auto;
     }
    
  2. 容器内容需要横向排列,不能换行

     .left-rolling-loading .left-rolling-loading-list {
       white-space: nowrap;
     }
    
  3. 获取内容的宽度方式与上划不同,上划取的是内容的高度,而左划取的是容器的滚动宽度

     // 获取内容区域宽度
     const scrollWidth = this.scrollElement?.scrollWidth || 0;
    
  4. 滚动距离获取的是scrollLeft

     // 获取滚动宽度
     const containerScrollWidth = this.scrollElement?.scrollLeft || 0;
    

点击查看代码 点击查看效果

实现一个上下划动滚动加载

上下划动比上划多了两个步骤:

  1. 判断划动的方向是上划还是下划

     const [scrollRecord, setScrollRecord, getScrollRecord] = useGetState({
       scrollTop: 0,
       direction: 'top',
     });
    
     // 计算滚动的方向,如果现在获取的滚动距离大于上一次的滚动距离则是上划,否则就是下划
     const direction =
         containerScrollHeight > getScrollRecord().scrollTop ? 'top' : 'bottom';
    
  2. 当下划时如果距离小于目标距离,则内容的前面增加内容

    
     // 如果上划时剩余距离小于指定距离或者下划时滚动距离小于指定距离,则加载数据
     if (
       (direction === 'top' && remainingDistance < SCROLL_LOADING_DISTANCE) ||
       (direction === 'bottom' && containerScrollHeight < remainingDistance)
     ) {
       handleLoadData();
     }
    
    
    
     // 上划时新增内容加到最后面
     if (getScrollRecord().direction === 'top') {
       setListData([...list, ...res]);
     } else {
       // 下划时新增内容加到最前面
       setListData([...res, ...list]);
     }
    
    

点击查看代码 点击查看效果

实现一个左右划动滚动加载

左右划动与上下划动原理基本一致,也是在左划的基础上增加两个步骤:

  1. 判断划动的方向是左划还是右划

    
      const [scrollRecord, setScrollRecord, getScrollRecord] = useGetState({
        scrollLeft: 0,
        direction: 'left',
      });
    
      // 计算滚动的方向,如果现在获取的滚动距离大于上一次的滚动距离则是左划,否则就是右划
      const direction =
      containerScrollWidth > getScrollRecord().scrollLeft ? 'left' : 'right';
    
    
  2. 当右划时如果距离小于目标距离,则内容的前面增加内容

    
     // 计算滚动的方向,如果现在获取的滚动距离大于上一次的滚动距离则是左划,否则就是右划
     const direction =
       containerScrollWidth > getScrollRecord().scrollLeft ? 'left' : 'right';
    
     // 如果左划时剩余距离小于指定距离或者右划时滚动距离小于指定距离,则加载数据
     if (
       (direction === 'left' && remainingDistance < SCROLL_LOADING_DISTANCE) ||
       (direction === 'right' && containerScrollWidth < remainingDistance)
     ) {
       handleLoadData();
     }
    
     setScrollRecord({ scrollLeft: containerScrollWidth, direction });
    
    
    
     // 左划时新增内容加到最后面
     if (getScrollRecord().direction === 'left') {
       setListData([...list, ...res]);
     } else {
       // 右划时新增内容加到最前面
       setListData([...res, ...list]);
     }
    
    

点击查看代码 点击查看效果