zoukankan      html  css  js  c++  java
  • vue实现虚拟列表

    当数据量较大(此处设定为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
     
  • 相关阅读:
    B-树和B+树
    线程与内核对象的同步-2
    线程与内核对象的同步
    高级线程同步 临界区
    Levenshtein Distance (编辑距离) 算法详解
    平衡二叉树
    静态查找表
    C++中的容器类详解
    How do I list all tables/indices contained in an SQLite database
    SmartGit STUDY 2
  • 原文地址:https://www.cnblogs.com/yf2196717/p/14689186.html
Copyright © 2011-2022 走看看