vue实现虚拟列表

摘要:
当数据量很大(此处设置为10w),需要以列表的形式呈现给用户时,如果我们不处理,在浏览器中渲染10wdom节点将非常耗时。例如,我的Macbookair,渲染10w条数据需要超过13秒才能看到页面(实际上大约需要10秒)。如果你是一个用户,你不会等待超过10秒的网页。我们可以使用虚拟列表逐步解决这个问题。首先,让我们看看效果。这是data data()中的数据{return{list:[]/

当数据量较大(此处设定为10w),而且要用列表的形式展现给用户,如果我们不做处理的话,在浏览器中渲染10w dom节点,是极其耗费时间的,那我的Macbook air举例,10w条数据渲染出来到能看到页面,需要13秒多(实际应该是10秒左右),如果是用户的话肯定是不会等一个网页十几秒的
在这里插入图片描述
我们可以用虚拟列表解决这个问题
一步步来
首先看一下效果
在这里插入图片描述

这是data中的数据

data() {
    return {
      list: [], // 贼大的数组
      li: {
        // 列表项信息
        height: 50,
      },
      container: {
        // 容器信息
        height: 500,
      },
      pos: 1, // 第一排显示的元素的下标
      MAX_NUM: 1, // 在容器内最多显示几个列表项
      timer: null, // 定时器
      carriedOut: true, // 能不能执行操作
    };
  },
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

然后在mounted中创建一个贼大的数组,在调用test方法计算第一次的虚拟列表中有哪些

mounted() {
    // 创建一个贼大的数据数组
    for (let i = 0; i < 100000; i++) {
      this.list.push(i);
    }
    this.test();
  },
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

test方法

test() {
      // 节流
      if (this.carriedOut) {
        // 容器跟里面的列表项
        const { container, li } = this;
        // 计算可视区域最多能显示多少个li
        this.MAX_NUM = Math.ceil(container.height / li.height);
        // 获取 overflow:scroll 的元素已滚动的高度
        let scrollTop = this.$refs.container.scrollTop;
        // 计算当前处于第一排的元素的下标
        this.pos = Math.round(scrollTop / li.height);
        // 下方节流操作
        this.carriedOut = false;
        this.timer = setTimeout(() => {
          this.carriedOut = true;
          clearTimeout(this.timer);
        }, 50);
      }
    },
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

然后是computed

computed: {
    // 用于渲染在页面上的数组
    showList() {
      // 根据计算出来的 第一排元素的下标,和最多显示多少个  用slice实现截取数组
      let arr = this.list.slice(this.pos, this.pos + this.MAX_NUM);
      return arr;
    },
  },
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这是html,注意监听了div的scroll事件,并且调用的是test方法

<div class="virtual-list">
    <h1>虚拟列表</h1>
    <div class="container" ref="container" :style="`height:${container.height}px`" @scroll="test">
      <ul :style="`height:${li.height*list.length}px;padding-top:${li.height*pos}px`">
        <li :style="`height:${li.height}px`" v-for="item in 100000" :key="item">{{item}}</li>
      </ul>
    </div>
  </div>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

完整源代码

<template>
  <div class="virtual-list">
    <h1>虚拟列表</h1>
    <div class="container" ref="container" :style="`height:${container.height}px`" @scroll="test">
      <ul :style="`height:${li.height*list.length}px;padding-top:${li.height*pos}px`">
        <li :style="`height:${li.height}px`" v-for="item of showList" :key="item">{{item}}</li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [], // 贼大的数组
      li: {
        // 列表项信息
        height: 50,
      },
      container: {
        // 容器信息
        height: 500,
      },
      pos: 1, // 第一排显示的元素的下标
      MAX_NUM: 1, // 在容器内最多显示几个列表项
      timer: null, // 定时器
      carriedOut: true, // 能不能执行操作
    };
  },
  mounted() {
    // 创建一个贼大的数据数组
    for (let i = 0; i < 1000; i++) {
      this.list.push(i);
    }
    this.test();
  },
  computed: {
    // 用于渲染在页面上的数组
    showList() {
      // 根据计算出来的 第一排元素的下标,和最多显示多少个  用slice实现截取数组
      let arr = this.list.slice(this.pos, this.pos + this.MAX_NUM);
      return arr;
    },
  },
  methods: {
    test() {
      // 节流
      if (this.carriedOut) {
        // 容器跟里面的列表项
        const { container, li } = this;
        // 计算可视区域最多能显示多少个li
        this.MAX_NUM = Math.ceil(container.height / li.height);
        // 获取 overflow:scroll 的元素已滚动的高度
        let scrollTop = this.$refs.container.scrollTop;
        // 计算当前处于第一排的元素的下标
        this.pos = Math.round(scrollTop / li.height);
        // 下方节流操作
        this.carriedOut = false;
        this.timer = setTimeout(() => {
          this.carriedOut = true;
          clearTimeout(this.timer);
        }, 50);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.virtual-list {
  text-align: center;
  .container {
    overflow: scroll;
    border: 1px solid red;
  }
}
</style>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
 

免责声明:文章转载自《vue实现虚拟列表》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇docker部署禅道及开启MySQL远程登录Git GUI如何汉化设置成中文?下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

移动端解决input被输入法挡住的问题

有过移动端web开发经验的人应该都会遇到这个问题,一个input在页面最底部或者偏下的位置,输入时由于输入法的弹出,在部分浏览器下由于不会自动计算window的高度,导致input被输入法挡住。本文的解决方式是利用scrollTop来解决,在input获取焦点后,动态地设置body的高度并设置scrollTop到指定位置,这样可以保证input会滚动到输入...

vue中el-upload上传多图片且携带参数,批量而不是一张一张的解决方案

现在前端基本不是vue技术栈就是react技术栈。 vue技术栈最常用的就是element-ui的ui框架了。 在项目中,我们经常会碰到这种需求:批量上传文件 element-ui 确实也为我们提供了<el-upload>这样的组件,同事也暴露了很多的属性和方法供我们使用。 但是很多人却碰到了这样的问题:项目需求是批量上传,但是为什么自己上传的...

vue跨域访问

第一次创建vue项目,画完静态页面一切顺利,准备和后台进行联调,问题来了,无论怎么调试使用Axios,jQuary还是使用原生的Ajax请求都访问不通(前提条件,另外一个人的电脑当成服务器,进行访问),然后各种百度查询了很多资料才明白我进行了跨域访问, 解决办法,修改config/index.js和config/prod.env.js文件 对config/...

Vue 打包成APP后首屏出现白屏问题

  1、npm run build打包后页面全屏空白   解决位置:config/index.js文件:把assetsPublicPath: '/'改为assetsPublicPath: './' 2、npm run build打包后  底部的选项卡正常显示,但是内容白屏,只有点击一次之后才能出现   解决位置:router/index.js 里 路由设置...

vue 解决jsonp跨域

在Vue中使用jsonp 参考链接:https://blog.csdn.net/m0_38134431/article/details/87930647 在vue中使用vue-jsonp 参考链接:https://www.jianshu.com/p/10901e13d794 参考链接:https://www.jianshu.com/p/e4379e6690...

vue刷新当前路由:router-view 复用组件时不刷新的3种解决方案总结

  vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。   对于路由,不同的路由跳转,vue...