Vue项目实践:使用滚动下拉分页优化大数据展示页面【通过防抖加标志位进行方案优化】

Vue项目实践:使用滚动下拉分页优化大数据展示页面

前言

        传统的分页机制通过点击页码来加载更多内容,虽然直观,但在处理大量数据时可能会导致用户体验不佳。相比之下,滚动下拉分页能够在用户滚动到页面底部时自动加载更多内容,既节省了用户操作,也使得数据的展示更加流畅自然。

准备工作

scrollTop,clientHeight,scrollHeight 详解

Vue项目实践:使用滚动下拉分页优化大数据展示页面

  1. scrollTop
    定义:scrollTop 属性表示元素在垂直方向上已经滚动过的距离。换句话说,它衡量的是元素内容顶部与视口顶部之间的距离。这个值通常是非负的,单位是像素。
    应用场景:当你需要知道元素内部滚动了多少或者想要手动设置滚动位置时,会用到这个属性。例如,实现“回到顶部”按钮功能时,可以设置 scrollTop0来瞬间返回顶部。
  2. clientHeight
    定义:clientHeight 表示元素可视区域的高度,即元素内容区的高度加上垂直边框和内边距(padding),但不包括水平滚动条(如果存在)、外边距或滚动条本身。这个值总是正的,单位也是像素。
    应用场景:当你需要计算元素实际显示给用户的高度时会用到 clientHeight,比如判断元素是否完全在视口内显示。
  3. scrollHeight
    定义:scrollHeight 表示元素的总高度,包括不可见的部分,也就是元素内容的总高度,不论内容是否在当前视口内可见。这包括了所有内边距、边框,但不包括外边距。对于没有滚动条的元素,scrollHeight 等于元素的 clientHeight
    应用场景:当你需要了解元素内容的完整高度,特别是用于判断是否还有更多内容可以滚动查看时,scrollHeight 就显得非常重要。比如,结合 scrollTopclientHeight来判断是否已经滚动到底部,从而实现无限滚动加载功能。

实现思路

在实现一个无限滚动(滚动加载更多)功能时,可以通过比较 scrollTop + clientHeightscrollHeight 来判断是否接近滚动底部。

实现

效果

Vue项目实践:使用滚动下拉分页优化大数据展示页面

HTML\CSS结构

注意:一定要设置需要滚动盒子device-content的高度,及其overflow: hidden; overflow-y: auto;样式属性,使其具有滚动。通过handleScroll进行监听父盒子的滚动状态,其中device-box是父盒子中的内容列表。

<a-spin dot :loading="deviceLoading" tip="正在加载...">
  <div class="device-content" @scroll="handleScroll">
    <div v-for="device in deviceList" :key="device.id" class="device-box">
      <div class="device-con-box">
        <div class="device-con-img"></div>
        <div class="device-con-text">
          <div class="device-con-text-top">{{
            device.detectDeviceFullName
          }}</div>
          <div class="device-con-text-bottom">
            <span
              v-if="device.runStatusKey === 'device_run_status:offline'"
              class="offline"
              >离线</span
            >
            <span
              v-if="device.runStatusKey === 'device_run_status:working'"
              class="working"
              >工作</span
            >
            <span
              v-if="device.runStatusKey === 'device_run_status:waiting'"
              class="waiting"
              >空闲</span
            >
            <span
              v-if="device.runStatusKey === 'device_run_status:breakdown'"
              class="breakdown"
              >故障</span
            >
          </div>
        </div>
      </div>
    </div>
  </div>
</a-spin>

CSS结构:

.device-content {
  width: 100%;
  height: 645px;
  overflow: hidden;
  overflow-y: auto;
  .device-box {
    cursor: pointer;
    height: 148px;
    width: 400px;
    float: left;
    border-radius: 12px;
    border: 1px solid #ccc;
    margin-bottom: 6px;
    margin-right: 6px;
    .device-con-box {
      height: 98px;
      width: 305px;
      margin: 0px auto;
      margin: 20px 68px 37px 48px;
      display: flex;
      .device-con-img {
        height: 80px;
        width: 80px;
        background: url('../../assets/images/deviceImg.png');
      }
      .device-con-text {
        width: 220px;
        height: 100%;
        padding-left: 16px;
        .device-con-text-top {
          height: 68px;
          width: 120%;
          padding-top: 23px;
          font-size: 14px;
          font-weight: 400;
          color: #000;
        }
        .device-con-text-bottom {
          height: 30px;
          width: 100%;
          font-family: Microsoft YaHei UI;
          font-size: 24px;
          font-weight: 700;
          line-height: 22px;
          text-align: left;
          color: #19cd61;
        }
        .line-division {
          margin-left: 10px;
          margin-right: 10px;
          color: #e7e7e7;
          font-size: 18px;
          position: relative;
          top: -3px;
        }
      }
    }
  }
}

监听父盒子函数handleScroll

检查用户是否已经滚动到容器的底部,如果滚动到了底部,再次判断页面的数据是否大于总条数,如果小于总条数,则继续进行加载下一页,如果大于总条数,则不进行加载。【距离顶部的距离+可视区高度>=元素总高度

// eslint-disable-next-line no-use-before-define
const handleScroll = (e: Event) => {
  const target = e.target as HTMLElement;
  // 检查用户是否已滚动到容器底部附近
  if (target.scrollTop + target.clientHeight >= target.scrollHeight - 10) {
    // 此条件检查是否还有更多页面的数据需要加载
    if (pagination.current * pagination.pageSize < pagination.total) {
      fetchData({ ...basePagination, current: pagination.current + 1 });
    }
  }
} 

但是会出现,当触底的时候,多次请求分页列表,导致页面存储的数据大于数据库中数据的总条数。

Vue项目实践:使用滚动下拉分页优化大数据展示页面
处理以上触底时多次请求有两种方式可解决

使用防抖技术

使用防抖技术,确保在短时间内只处理一次滚动事件。

// 防抖函数
function debounce(func: any, wait: any) {
  let timeout: number | undefined;

  // eslint-disable-next-line func-names
  return function (...args: any[]) {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const context: any = this;

    clearTimeout(timeout);
    timeout = window.setTimeout(() => {
      func.apply(context, args);
    }, wait);
  };
}

添加标志位

添加一个标志位isFetching 来防止在请求完成之前再次发送请求。

const isFetching = ref(false);

const fetchData = async (
  params: PolicyParams = { current: 1, pageSize: 20 }
) => {
  if (isFetching.value) return;
  isFetching.value = true;
  setLoading(true);
  try {
    const { data } = await getDetectDeviceMonitorPage(params);
    pagination.current = params.current;
    pagination.total = data.total;
    if (params.current === 1) {
      deviceList.value = data.data;
    } else {
      deviceList.value = [...deviceList.value, ...data.data];
    }
  } catch (err) {
    // you can report use errorHandler or other
  } finally {
    setLoading(false);
    isFetching.value = false;
  }
};

const handleScroll = (e: Event) => {
  const target = e.target as HTMLElement;
  // 检查用户是否已滚动到容器底部附近
  if (target.scrollTop + target.clientHeight >= target.scrollHeight - 10) {
    // 此条件检查是否还有更多页面的数据需要加载
    if (!isFetching.value && pagination.current * pagination.pageSize < pagination.total) {
      fetchData({ ...basePagination, current: pagination.current + 1 });
    }
  }
};

通过添加防抖和标志位后的效果
Vue项目实践:使用滚动下拉分页优化大数据展示页面
完美解决触底出现多次分页请求。

相关推荐

  1. 数据查询深优化方案

    2024-06-12 07:50:02       10 阅读
  2. 优化Vue载速度的实用方法

    2024-06-12 07:50:02       53 阅读
  3. 优化Vue载速度的实用方法

    2024-06-12 07:50:02       34 阅读
  4. vue 项目实现

    2024-06-12 07:50:02       32 阅读
  5. 原生小程序/上载(通过页面生命周期)

    2024-06-12 07:50:02       11 阅读
  6. 数据优化,应对PageHelper

    2024-06-12 07:50:02       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-12 07:50:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-12 07:50:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-12 07:50:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-12 07:50:02       20 阅读

热门阅读

  1. 爬取京东商品图片的Python实现方法

    2024-06-12 07:50:02       6 阅读
  2. Oracle 存储过程

    2024-06-12 07:50:02       6 阅读
  3. 嵌入式Linux中OpenSSH移植到ARM开发板

    2024-06-12 07:50:02       8 阅读
  4. Redis的数据淘汰策略和集群部署

    2024-06-12 07:50:02       8 阅读
  5. 基于python的PDF文件解析器汇总

    2024-06-12 07:50:02       9 阅读
  6. Web前端开发PDF:技术与挑战的深度剖析

    2024-06-12 07:50:02       10 阅读
  7. 深度学习-使用 Bash 脚本

    2024-06-12 07:50:02       7 阅读
  8. C++中的抽象工厂模式

    2024-06-12 07:50:02       7 阅读
  9. 关于Flutter doctor里两个警告的消除

    2024-06-12 07:50:02       9 阅读
  10. 深度探索Copilot插件

    2024-06-12 07:50:02       6 阅读
  11. elasticsearch快照生成与恢复

    2024-06-12 07:50:02       8 阅读