vue 虚拟列表

虚拟列表

什么是虚拟列表

虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术

为什么需要虚拟列表

虚拟列表是对长列表的一种优化方案。在前端开发中,会碰到一些不能使用分页方式来加载列表数据的业务形态,我们称这种列表叫做长列表。比如,手机端,淘宝商品展示,美团外卖等,数据量特别庞大,不适合分页,以及懒加载,这时候我们可以采用虚拟列表,只展示可视区域数据。

直接上代码

HTML

  <div>
    <div class="list-view" ref="container" @scroll="handleScroll">
      <div class="list-view-phantom" ref="clientHeight" :style="{ height: contentHeight + 'px' }"></div>
      <ul ref="content" class="list-view-content">
        <li class="list-view-item" :style="{ height: itemHeight + 'px' }" :key="index" v-for="(val, index) in list">
          {{ val }}
        </li>
      </ul>
    </div>
  </div>

js

export default {
  name: 'ListView',
  computed: {
    contentHeight() {
      // 计算滚动条高度
      return this.data.length * this.itemHeight;
    }
  },

  mounted() {
    this.getData();
    this.update();
  },

  data() {
    return {
      data: [], // 总数据
      itemHeight: 30, // 单个高度
      list: [], // 渲染数据
    };
  },

  methods: {
    update(scrollTop = 0) {
      // 获取当前可展示数量
      const count = Math.ceil(this.$el.clientHeight / this.itemHeight);
      // 取得可见区域的起始数据索引
      const start = Math.floor(scrollTop / this.itemHeight);
      // 取得可见区域的结束数据索引
      const end = start + count;

      // 计算出可见区域对应的数据,让 Vue.js 更新
      this.list = this.data.slice(start, end);

      // 把可见区域的 top 设置为起始元素在整个列表中的位置(使用 transform 是为了更好的性能)
      this.$refs.content.style.webkitTransform = `translate3d(0, ${ start * this.itemHeight }px, 0)`;
    },
    handleScroll(e) {
      // 获取当前滚动条滚动位置
      const scrollTop = this.$refs.container.scrollTop;
      this.update(scrollTop);
    },
    getData() {
      //创建模拟数据
      let data = [];
      for (let i = 0; i < 1000000; i++) {
          data.push(`第 ${i} 个数据`)
      }
      this.data = [...data];
    }
  }
}

CSS

.list-view {
    width: 400px;
    height: 400px;
    overflow: auto;
    position: relative;
    border: 1px solid #c1c1c1;
    box-shadow: 3px 3px 5px #ccc;
  }

  .list-view-phantom {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
  }

  .list-view-content {
    left: 0;
    right: 0;
    top: 0;
    position: relative;
  }

  .list-view-item {
    padding: 6px;
    color: #999;
    line-height: 30px;
  }
posted @ 2020-11-19 11:21  渡心°  阅读(2026)  评论(0编辑  收藏  举报