vue虚拟列表

114 阅读1分钟

虚拟列表

// 实现思路,在scroll事件中,每次计算出当前的开始位置(this.scrollTop / this.itemHeight)
和结束位置,计算出现在所处的位置,在用css绝对定位。
<template>
  <div
    ref="contentBox"
    class="content-box"
    :style="{ height: contentHeight + 'px' }"
    @scroll="scrollListener"
  >
    <div
      :style="{
        position: 'relative',
        height: showBoxHeight
      }"
    >
      <div
        :style="{
          position: 'absolute',
          top: top + 'px'
        }"
      >
        <div
          class="box-item"
          :style="{
            height: itemHeight + 'px',
            lineHeight: itemHeight + 'px'
          }"
          v-for="(item, index) of showList"
          :key="index"
        >
          {{ item }}
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'virtualList',
  data() {
    return {
      total: 1000000, //模拟数据总数
      contentHeight: 400,
      showList: [],
      list: [],
      startIndex: 0,
      endIndex: null,
      itemHeight: 30,
      scrollTop: 0, //卷起高度
      showNum: 10, //当前显示列表个数
      top: 0 //距离顶部距离
    }
  },
  computed: {
    showBoxHeight() {
      return this.itemHeight * this.list.length + 'px'
    }
  },
  mounted() {
    this.getList()
    this.scrollListener()
  },
  methods: {
    getList() {
      // 构造虚拟数据
      this.list = Array.from({ length: this.total }).map(
        (_, index) => `第${index + 1}条数据`
      )
    },
    scrollListener() {
      this.scrollTop = this.$refs.contentBox.scrollTop // 获取距离顶部距离
      // this.showNum = Math.ceil(this.contentHeight / this.itemHeight) // 可展示个数
      this.startIndex = Math.floor(this.scrollTop / this.itemHeight) // 起点位置
      this.endIndex = this.startIndex + 10 // 结束位置
      this.showList = this.list.slice(this.startIndex, this.endIndex) // 当前查看数据
      this.top = this.startIndex * this.itemHeight // 距离顶部的距离,控制内容出现在可视区域
    }
  }
}
</script>

<style scoped>
.content-box {
  margin: 30px auto 0;
  position: relative;
  width: 400px;
  border: 1px solid #e4e7ed;
  overflow-y: auto;
  box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
  border-radius: 4px;
  padding: 10px 0;
}
.box-item {
  padding: 0 32px 0 20px;
  color: #606266;
}
.content-box::-webkit-scrollbar {
  width: 10px;
  height: 1px;
}
.content-box::-webkit-scrollbar-thumb {
  border-radius: 10px;
  background: #e5e5e5;
}
.content-box::-webkit-scrollbar-track {
  border-radius: 10px;
  background: #ffffff;
}
</style>