首页 > 其他分享 >一个很基础的虚拟滚动

一个很基础的虚拟滚动

时间:2023-11-16 15:56:05浏览次数:34  
标签:flex 虚拟 滚动 基础 scrollBox scrollTop currentPage scrollHeight const

由于项目中要写一个虚拟滚动,但不能下插件,所以就手写实现了一版,很基础。

主要难点是要动态计算第几屏

主要思想是算出真实高度是滚动高度的几倍,然后*100,在用视口已滚动的最大页数*这个倍数在除以这个倍数

不理解这个逻辑

如果不考虑精度

也可以通过滚动的真实距离除以视口大小,来计算第几屏

 
<template>
  <div class="listBox">
    <div class="topBox">
      <div class="left">
        <DocumentSvg />
        <span>待办事项</span>
      </div>
      <div class="right">共{{ currentPage+1 }}/{{ totalPages+1 }}页</div>
    </div>
    <ul ref="middleList" class="middleList scrollBox" @scroll="handleScroll">
      <li v-for="(item, index) in agencyList.slice(0, sliceIndex)" :key="item.msgSendId+item.msgReceiveId">
        <span class="order">{{ index + 1 }}</span>
        <span class="middleList-content">{{ item.msgTitle }}</span>
        <div class="btn">处理</div>
      </li>
    </ul>
    <!-- <div v-if="agencyList.length>8&&sliceIndex===8" class="more" @click="sliceIndex=9999">查看更多</div>
    <div v-else-if="sliceIndex>8&&currentPage>1" class="more" @click="backTop">收起</div>
    <div v-else class="more" style="opacity:0" >占位元素</div> -->
  </div>
</template>
<script>
import DocumentSvg from './documentSvg.vue'
import { queryNoReadAgencyList } from '../../index.api'
export default {
  components: {
    DocumentSvg
  },
  data() {
    return {
      agencyList: [],
      count: 0,
      sliceIndex: 8,
      currentPage: 0,
      hasMore: false,
      prevScrollPosition: 0,
      prePage: 0
    }
  },
  computed: {
    totalPages() {
      return Math.ceil(this.count / 8)
    }
  },
  mounted() {
    const params = {
      msgType: 'agency',
      receiveUser: this.$store.getters.userInfo.userId,
      appId: this.$store.getters.userInfo.appId,
      tenantId: this.$store.getters.userInfo.tenantId,
      searchDate: 'sms',
      pageSize: 9999
    }
    queryNoReadAgencyList(params).then((res) => {
      this.agencyList = res.datas
      this.count = res.count
      console.log(res, 'r0-')
    })
  },
  methods: {
    handleScroll() {
      // 获取滚动容器
      const scrollBox = this.$refs.middleList

      const scrollTop = scrollBox.scrollTop
      // clientHeight:可见高度
      // scrollBox.scrollHeight:整个容器的高度
      // scrollHeight:滚动高度
      const scrollHeight = scrollBox.scrollHeight - scrollBox.clientHeight
      const scrollPercentage = (scrollTop / scrollHeight) * 100
      // 如果加载完成
      if (this.hasMore) {
      // 计算当前所在的页数
        this.currentPage = Math.ceil((this.totalPages * scrollPercentage) / 100)
        return
      }
      // 如果回滚
      if (scrollTop < this.prevScrollPosition) {
        this.currentPage = Math.ceil((this.prePage * scrollPercentage) / 100)
        this.prevScrollPosition = scrollTop
        return
      }
      this.prevScrollPosition = scrollTop

      const scrollBottom = scrollBox.scrollHeight - (scrollBox.scrollTop + scrollBox.clientHeight)
      // 如果并非加载完成也并非回滚,但距离底部大于50
      if (scrollBottom > 50) {
        this.currentPage = Math.ceil((this.prePage * scrollPercentage) / 100)
        return
      } else {
        this.sliceIndex = this.sliceIndex + 8
        if (this.currentPage < this.totalPages) {
          this.currentPage++
          this.prePage = this.currentPage
        } else {
          this.hasMore = true
        }
      }
    }
  }
}
</script>
<style lang='scss' scoped>
.listBox {
  width: 38vw;
  margin: 0 auto;
  .topBox {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: #fff;
    .left {
      display: flex;
      align-items: center;
    }
    .right {
      margin-right: 20px;
    }
  }

  .middleList {
    height: 69vh;
    // display: flex;
    // flex-direction: column;
    // justify-content: flex-start;
    overflow-y: scroll;
    li {
      cursor: pointer;
      width: 100%;
      height: 7vh;
      border-radius: 10px;
      color: #fff;
      list-style-type: none;
      display: flex;
      justify-content: space-between;
      align-items: center;
      white-space: nowrap; /* 防止文本换行 */
      overflow: hidden; /* 控制超出部分的隐藏 */
      text-overflow: ellipsis; /* 显示省略号 */
      font-size: 16px;
      margin: 1.5vh 0;
      .order {
        text-align: center;
        flex: 1;
      }
      .middleList-content {
        flex: 8;
      }
      .btn {
        user-select: none;
        text-align: center;
        margin-right: 10px;
        width: 5.6vw;
        height: 4.5vh;
        line-height: 4.5vh;
        border-radius: 20px;
        font-size: 16px;
        // transition: all 1s;
      }
    }
  }
  .more {
    user-select: none;
    opacity: 0.57;
    color: #ffffff;
    font-size: 16px;
    text-align: center;
    cursor: pointer;
  }
}
</style>
<style lang="scss" scoped>
@import "./../loginAfterCss/themeModule.scss";
</style>

 

标签:flex,虚拟,滚动,基础,scrollBox,scrollTop,currentPage,scrollHeight,const
From: https://www.cnblogs.com/truegrit/p/17836470.html

相关文章

  • skywalking(三) 实现收集基于虚拟机环境dubbo微服务链路跟踪案例
    dubbo微服务架构https://cn.dubbo.apache.org/zh-cn/overview/home/https://help.aliyun.com/zh/edas/developer-reference/dubbo-overview‍1.安装zookeeper注册中心官网:https://zookeeper.apache.org/安装说明:https://zookeeper.apache.org/doc/r3.7.1/zookeeperAdmin.......
  • Git使用基础
    Git是什么?Git是一个版本控制系统,用于跟踪文件和项目的变化。它可以帮助多个开发者在同一个项目上协同工作,同时还能够追踪项目的历史和变更。 本地仓库和远程仓库本地仓库:本地仓库是存储在你自己计算机上的Git仓库。当你在项目文件夹中运行gitinit命令时,它会初始化一......
  • 一个虚拟主机上放多个网站(asp.net)
    Asp.net不像Asp一样,建个文件夹就能放一个程序,互不干扰,为了让一个虚拟主机能放多个Asp.net,查找了不少资料,没有一个答案是完美的,不过有些资料倒给了我一些启发,通过思考,加上实践,终于探索出一个新路子,实现了能简单提出为一个网站,也能合并的方案。同时感谢菜菜灰的帮助,请看实现的效果首......
  • 【Java基础】方法重载
    命名方法命名:小驼峰类命名:大驼峰方法重载调用方法时,JVM会通过参数的不同区分同名的方法好处:不需要记忆过多繁琐的方法名字......
  • 【Java基础】Java基础知识 && 数据类型转换 && 运算符
    1.JVMJREJDK三者的作用和关系JDK:javadevelopmentkit,java开发工具包,用来开发Java程序的,针对java开发者;JDK即为Java开发工具包,包含编写Java程序所必须的编译、运行等开发工具以及JRE。开发工具如:用于编译Java程序的javac命令;用于启动JVM运行Java程序的Ja......
  • 1-1 计算机基础和py环境搭建
    ​1.计算机基础1.1基本概念计算机组成:计算机是由多个硬件组合而成的东西,常见的硬件有:CPU、硬盘、内存、网卡、显示器、机箱、电源等等但单纯地组合并不能协作操作系统:用于协调计算机各个硬件,让硬件之间进行协同工作,以完成某个目标常见的操作系统:windows-xp\win7\win1......
  • 1-3 Python基础语法
    ​ 目录1.循环语句1.1循环语句基本使用1.2综合案例1.3break1.4continue1.5whileelse2.字符串格式化2.1%2.1.1基本格式化操作2.1.2百分比2.2format(推荐)2.3f3.运算符3.1运算符优先级3.2判断题 1.循环语句while循环for循环```while条件: ......
  • 1-2 Python基础语法
    ​ 1.编码计算机所有的数据本质上是以0和1的组合来存储在计算机中会将中文转换为0101010100最终存储到硬盘上计算机中有一个编码的概念(也就是密码本)  武  ->   0111111100011010010110110在计算机中有很多种编码每种编码都有自己的一套密码本,都维护这......
  • 掌握终端基础技巧:Linux下的文件和目录复制操作
    1.cp命令:在Linux中,cp命令用于复制文件和目录。基本语法如下:cp[选项]源文件目标文件其中,源文件是要复制的文件名,目标文件是复制后的新文件名或路径。2.复制单个文件:要复制单个文件,只需指定源文件和目标路径即可。例如,将文件file.txt复制到目录path下:cpfile.......
  • 【scipy 基础】--正交距离回归
    Scipy的ODR正交距离回归(ODR-OrthogonalDistanceRegression)模块,适用于回归分析时,因变量和自变量之间存在非线性关系的情况。它提高了回归分析的准确性和稳健性。对于需要解决非线性回归问题的科研人员和工程师来说,它具有非常重要的意义。ODR正交距离回归模块的作用主要在于它将......