PC端实现滚动分页懒加载

news2024/9/30 5:22:33

思路

  • 监听列表元素的滚动事件,滚动到底部的时候,加载下一页的数据
  • 监听数据加载,判断是否已全部加载结束

实现

监听滚动事件

  • 为列表元素 listBox 绑定 scroll 事件进行监听
<div class="listBox" @scroll="watchScroll">
  <div class="sinList" v-for="(item, index) in dataList" :key="index">
    {{ item.label }}--{{ item.value }}
  </div>
  <div class="dataDesc">
    {{
      dataList.length == 0
        ? "暂无数据"
        : loading && !finished
        ? "加载中"
        : "没有更多了"
    }}
  </div>
</div>
  • scrollTop:listBox 滚动时,向上卷曲出去的距离
  • clientHeight:listBox 滚动时,可视的高度
  • scrollHeight:listBox 的总高度
  • 滚动的过程中,scrollTop 不断变大,直至 scrollTop + clientHeight == scrollHeight 时,表示 listBox 已经滚动到了底部
  • 滚动到底部时,如果 finished 为 false,表示数据还未加载完,此时需要调用接口,加载下一页的数据
  • 加载完数据后,scrollHeight 变大
  • 继续滚动,scrollTop 变大,直至再次 scrollTop + clientHeight == scrollHeight …
  • 为了优化体验,可以使“调用接口”提前触发,即在距离底部一定距离时,就触发接口加载。
  • 此距离取个名字为安全距离 safeHeight,即 scrollTop + clientHeight >= scrollHeight - safeHeight 时,触发接口调用

在这里插入图片描述

// 监听滚动事件
watchScroll(e) {
  let scrollTop = e.target.scrollTop; // listBox 滚动条向上卷曲出去的长度,随滚动变化
  let clientHeight = e.target.clientHeight; // listBox 的视口可见高度,固定不变
  let scrollHeight = e.target.scrollHeight; // listBox 的整体高度,随数据加载变化
  let saveHeight = 30; // 安全距离,距离底部XX时,触发加载
  let tempVal = scrollTop + clientHeight + saveHeight; // 向上卷曲距离 + 视口可见高度 + 安全距离
  console.log(
    "scrollTop:" +
      scrollTop +
      ";clientHeight:" +
      clientHeight +
      ";scrollHeight:" +
      scrollHeight,
    ";tempVal:" + tempVal
  );
  // 如果不加入 saveHeight 安全距离,在 scrollTop + clientHeight == scrollHeight 时,触发加载
  // 加入安全距离,相当于在 scrollTop + clientHeight >= scrollHeight - 30 时,触发加载,比前者更早触发
  if (tempVal >= scrollHeight) {
    console.log("滚动到底了");
    if (!this.finished && !this.switch) {
      // 数据加载未结束 && 未加锁
      this.getData();
    }
    this.switch = true; // 加锁,防止重复触发
  } else {
    console.log("还没有滚动到底");
  }
},

请求接口数据

  • 当 res.data 的条数 < pageSize 的时候,说明数据已经请求完毕
  • 当 dataList 的条数 == total 时,说明数据已经请求完毕
  • 以上两种情况可以将全局变量 finished 置为 true
  • 其他情况视为加载还未结束,将 finished 置为 false,页码自加 1,改变滚动锁的状态
  • 滚动锁 switch 用来防止接口被重复请求。当滚动到达底部时,请求接口时,将 switch 置为 true,即使再次触发 tempVal >= scrollHeight 也不再执行数据请求。
  • 直到请求到数据,并且判断数据还未加载完,则将 switch 置为 false,可以进入下次滚动判断
getData() {
  let params = {
    pageSize: this.pageSize,
    pageNum: this.pageNum,
  };
  this.loading = true;
  this.mockList(params).then((res) => {
    this.loading = false;
    if (res.code == 200) {
      if (res.data && res.data.length > 0) {
        this.dataList = this.dataList.concat(res.data);
        this.total = res.totalCount;
        if (
          res.data.length < this.pageSize ||
          this.dataList.length >= this.total
        ) {
          // 返回结果条数少于请求条数,认为已结束
          // 目前数据条数等于总条数,认为已结束
          this.finished = true;
        } else {
          this.finished = false;
          this.pageNum += 1; // 页码加1
          this.switch = false; // 还可以继续加载,改变锁状态
        }
      }
    }
  });
},

图示

在这里插入图片描述
在这里插入图片描述

完整代码

<template>
  <div class="page">
    <div class="listBox" @scroll="watchScroll">
      <div class="sinList" v-for="(item, index) in dataList" :key="index">
        {{ item.label }}--{{ item.value }}
      </div>
      <div class="dataDesc">
        {{
          dataList.length == 0
            ? "暂无数据"
            : loading && !finished
            ? "加载中"
            : "没有更多了"
        }}
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      pageSize: 10,
      pageNum: 1,
      total: 0,
      loading: false,
      finished: true,
      switch: false, // 加锁,防止滚动时,判断条件重复调用
      dataList: [],
    };
  },
  mounted() {
    this.getData();
  },
  methods: {
    getData() {
      let params = {
        pageSize: this.pageSize,
        pageNum: this.pageNum,
      };
      this.loading = true;
      this.mockList(params).then((res) => {
        this.loading = false;
        if (res.code == 200) {
          if (res.data && res.data.length > 0) {
            this.dataList = this.dataList.concat(res.data);
            this.total = res.totalCount;
            if (
              res.data.length < this.pageSize ||
              this.dataList.length >= this.total
            ) {
              // 返回结果条数少于请求条数,认为已结束
              // 目前数据条数等于总条数,认为已结束
              this.finished = true;
            } else {
              this.finished = false;
              this.pageNum += 1; // 页码加1
              this.switch = false; // 还可以继续加载,改变锁状态
            }
          }
        }
      });
    },
    // 模拟请求接口
    mockList(params) {
      console.log("请求接口 params", params);
      return new Promise((resolve, reject) => {
        let data = [];
        for (let i = 0; i < 58; i++) {
          data.push({
            value: "value" + i,
            label: "label" + i,
          });
        }
        // 模拟分页
        let tempArr = data.splice(
          params.pageSize * (params.pageNum - 1),
          params.pageSize * params.pageNum
        );
        let res = {
          data: tempArr,
          totalCount: data.length,
          pageSize: params.pageSize,
          pageNum: params.pageNum,
          code: 200,
          msg: "success",
        };
        setTimeout(() => {
          resolve(res);
        }, 100);
      });
    },
    // 监听滚动事件
    watchScroll(e) {
      let scrollTop = e.target.scrollTop; // listBox 滚动条向上卷曲出去的长度,随滚动变化
      let clientHeight = e.target.clientHeight; // listBox 的视口可见高度,固定不变
      let scrollHeight = e.target.scrollHeight; // listBox 的整体高度,随数据加载变化
      let saveHeight = 30; // 安全距离,距离底部XX时,触发加载
      let tempVal = scrollTop + clientHeight + saveHeight; // 向上卷曲距离 + 视口可见高度 + 安全距离
      console.log(
        "scrollTop:" +
          scrollTop +
          ";clientHeight:" +
          clientHeight +
          ";scrollHeight:" +
          scrollHeight,
        ";tempVal:" + tempVal
      );
      // 如果不加入 saveHeight 安全距离,在 scrollTop + clientHeight == scrollHeight 时,触发加载
      // 加入安全距离,相当于在 scrollTop + clientHeight >= scrollHeight - 30 时,触发加载,比前者更早触发
      if (tempVal >= scrollHeight) {
        console.log("滚动到底了");
        if (!this.finished && !this.switch) {
          // 数据加载未结束 && 未加锁
          this.getData();
        }
        this.switch = true; // 加锁,防止重复触发
      } else {
        console.log("还没有滚动到底");
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.page {
  width: 100%;
  height: 100vh;
  background: #f1f1f1;
  .listBox {
    background: #fff;
    width: 600px;
    height: 300px;
    overflow: auto;
    padding: 20px;
    box-sizing: border-box;
    .sinList {
      height: 40px;
      line-height: 40px;
    }
    .dataDesc {
      color: #999;
      text-align: center;
    }
  }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/737196.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Github点赞120k的Spring全家桶笔记,吃透Offer拿到手软!

Spring框架自诞生以来一直备受开发者青睐&#xff0c;有人亲切的称之为&#xff1a;Spring 全家桶。它包SpringMVC、SpringBoot、Spring Cloud、Spring Data等解决方案。 很多研发人员把spring看作心目中最好的java项目&#xff0c;没有之一。Spring系列包含非常多的项目&…

【LLM】DeepSpeed分布式训练框架

文章目录 一、DeepSpeed介绍1. 分布式背景介绍2. deepspeed介绍 二、deepspeedtransformer代码实战1. 预处理和Json文件2. 训练代码 三、deepspeed加速Bloom lora微调1. 配置文件2. 训练代码 Reference 一、DeepSpeed介绍 1. 分布式背景介绍 分布式计算环境中&#xff0c;主节…

进程间通信方法——命名管道

命名管道 匿名管道应用的一个限制就是只能在具有共同祖先&#xff08;具有亲缘关系&#xff09;的进程间通信。如果我们想在不相关的进程之间交换数据&#xff0c;可以使用FIFO文件来做这项工作&#xff0c;它经常被称为命名管道。&#xff08;命名管道是有文件名的&#xff0…

Vs窗口布局移动窗口vs直接卡死2

(1条消息) Vs窗口布局移动窗口vs直接卡死_vs拖动窗口布局卡死_Ma_Hong_Kai的博客-CSDN博客 由于莫名其妙的更新导致又卡死了&#xff0c;导致最近一年多无法拖动vs的框挺折磨 前一段时间看到一个有意思的命令 搞了搞了 可以拖动了&#xff08;目测应该是微软自己发现这个问…

【图像识别】openCV基础知识

图像处理基础 一、使用OpenCV前要准备的工作1.先导入需要用到的库2.自定义&#xff0c;图片展示函数 二、开始学习常用函数1.生成随机整数①. 函数说明②.代码a. 二维灰度图b. 三维彩色图 ③.代码现象a. 二维灰度图b. 三维彩色图 2.通道的分离与合并①先导入一张图片② 将其RGB…

多元回归预测 | Matlab基于麻雀算法(SSA)优化高斯过程回归(SSA-GPR)的数据回归预测,matlab代码,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于麻雀算法(SSA)优化高斯过程回归(SSA-GPR)的数据回归预测,matlab代码,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

合宙Air001震撼来袭!

Air001芯片特性 采用ARM 32位的M0内核&#xff0c;主频可达48MHz&#xff1b; 4K RAM32K Flash&#xff1b; 1.7&#xff5e;5.5V超宽范围供电&#xff0c;USB和电池都能直接供电&#xff1b; 内嵌可配4/8/16/22.12/24MHz的RC振荡器&#xff0c;无需外挂晶振就能48MHz运行…

你连存活到JDK8中著名的Bug都不知道,你怎么敢跳槽涨薪的?

在笔者研究 JDK 源码时&#xff0c;注意到在CopyOnWriteArrayList 和ArrayList 的构造器中都出现了如下 bug 字样 6260652 其实代表的JDK bug 列表中的编号 http://bugs.java.com/bugdatabase/view_bug.do?bug_id6260652 http://bugs.java.com/bugdatabase/view_bug.do?bug…

GBU808-ASEMI薄体整流桥GBU808

编辑&#xff1a;ll GBU808-ASEMI薄体整流桥GBU808 型号&#xff1a;GBU808 品牌&#xff1a;ASEMI 芯片个数&#xff1a;4 封装&#xff1a;GBU-4 恢复时间&#xff1a;≥2000ns 工作温度&#xff1a;-50C~150C 浪涌电流&#xff1a;200A 正向电流&#xff1a;8A 反…

Golang 命令源码文件

Go 语言标准库中专门用于接收和解析命令参数。这个代码包的名字叫 flag。 函数 flag.StringVar 接受 4 个参数。 第 1 个参数是用于存储该命令参数值的地址&#xff0c;具体到这里就是在前面声明的变量 name 的地 址了&#xff0c;由表达式 &name 表示。 第 2 个参数是为…

高级运维开发工程师带你处理linux木马(挖矿病毒)实战例子

一、事态描述 centos7测试服务器&#xff0c;突然密码登不上去了&#xff0c;然后CPU占100%。已经猜到&#xff0c;登录密码过于简单&#xff0c;密码被破解挂马了。大概率是CPU挖矿病毒。 二、重置centos7登录root密码 步骤1 启动Linux Centos7系统&#xff0c;当出现如下画…

JavaWeb JSP 内置对象

1.JSP 内置对象 在jsp自动转换成的java文件的service方法中&#xff0c;我们可以看到这九个内置对象&#xff1a; 具体如下&#xff1a; request&#xff08;HttpServletRequest&#xff09;&#xff1a;代表客户端的HTTP请求。通过该对象&#xff0c;可以获取请求参数、请求…

时序区间预测 | Matlab基于高斯过程回归(GPR)时间序列区间预测,matlab代码,单变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于高斯过程回归(GPR)时间序列区间预测,matlab代码,单变量输入模型 评价指标包括:MAE、MBE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %% 清空环境变量…

【Spring Boot丨(十 )】日志

上文讲了 类型安全配置属性 本篇来讲一下 Spring boot 的默认日志相关 Logging &#x1f351; 概述&#x1f34f; 日志格式&#x1f350; 控制台输出&#x1f965; 文件输出&#x1f95d; 文件轮换&#x1f352; 文件级别 &#x1f351; 概述 Spring Boot在所有内部日志中使用C…

支持裸耳3D空间音频?7月12日发布,荣耀Magic系列喜迎新成员

荣耀在7月12日将举办全场景新品发布会&#xff0c;其中将正式推出荣耀新款平板 MagicPad。 荣耀官方今天上午开始预热荣耀平板 MagicPad&#xff0c;官方海报文案表明这将成为首款支持裸耳3D空间音频的平板&#xff0c;引领行业潮流。 “空间音频技术”并不陌生&#xff0c;简…

git merge 与 git rebase 的区别

文章目录 前言1、使用 merge2、使用 rebase总结 前言 首先我们要清楚&#xff0c;git merge 与 git rebase 处理的问题是一样的&#xff0c;这两个命令都用于把一个分支的变更整合进另一个分支&#xff0c;只不过他们达成同样目的的方式不同。 刚开始&#xff0c;已经存在一…

Jmeter 做接口自动化测试的这些技巧你都掌握了吗

前言 JMeter 最初被设计用于 Web 应用测试&#xff0c;但后来扩展到了其他测试领域&#xff0c;可用于测试静态和动态资源&#xff0c;如静态文件、Java 小服务程序、CGI 脚本、Java 对象、数据库和 FTP 服务器等等。JMeter 可对服务器、网络或对象模拟巨大的负载&#xff0c;…

DBF文件的解析介绍

1.基本介绍 DBF是Digital Beam Forming的缩写&#xff0c;“.dbf”文件扩展名代表据库处理系统所产生的数据库文件&#xff0c;起初意为保存数据的文件是一个简单的表&#xff0c;可以使用ASCII字符集添加、修改、删除或打印数据&#xff0c;随着产品变得越来越流行&#xff0…

SIN65 DM蓝牙5.2双模热插拔PCB

键盘使用说明索引&#xff08;均为出厂默认值&#xff09; 软件支持&#xff08;驱动的详细使用帮助&#xff09;一些常见问题解答&#xff08;FAQ&#xff09;首次使用步骤蓝牙配对规则&#xff08;重要&#xff09;蓝牙和USB切换键盘默认层默认触发层0的FN键配置的功能默认功…

idea连接远程MySQL数据库

填写URL&#xff0c;以mysql为例 格式 jdbc:mysql://ip地址:端口号/数据库名 jdbc:mysql://127.0.0.1:3306/ldentification _Information