Vue 虚拟列表

233 阅读1分钟
  <div id="virtual" ref="list" class="infinite-list-container" @scroll="scrollEvent($event)">
    <div class="infinite-list-phantom" :style="{ height: listHeight + 'px' }"></div>
    <div class="infinite-list" :style="{ transform: getTransform }">
      <div ref="items" class="infinite-list-item card_inside" v-for="(card,index) in visibleData" @click="cardClick(card,index)" :class="{'bgc_red': card==listData[0],'bgc_yellow': card.yel,'box': card.newData}" :style="{ height: itemSize + 'px'}">
        <!-- // ,lineHeight: itemSize + 'px'  -->
        <el-row>
          <el-col :span="20">
            <div>车牌号:{{ card.car_number }}</div>
              <div>时间:{{ card.start_time }}</div>
                <div>类型:
                  <span v-for="s in allType">
                    <span v-if="card.type == s.type">{{ s.name }} - {{card.num}}次</span>
                  </span>
                </div>
          </el-col>
          <el-col :span="4">
            <i class="el-icon-video-play" @click.stop="showVideos(card)" style="font-size:50px;padding-top:10px;margin-left:-10px"></i>
          </el-col>
        </el-row>
      </div>
    </div>
  </div>
  data() {
    return {
      //可视区域高度
      screenHeight: 0,
      //偏移量
      startOffset: 0,
      //起始索引
      start: 0,
      //结束索引
      end: null,
      }
  },
  methods:{
      scrollEvent() {
          //当前滚动位置
          let scrollTop = this.$refs.list.scrollTop;
          //此时的开始索引
          this.start = Math.floor(scrollTop / this.itemSize);
          //此时的结束索引
          this.end = this.start + this.visibleCount;
          //此时的偏移量
          this.startOffset = scrollTop - (scrollTop % this.itemSize);
      },
      zeroLength() {
          this.screenHeight = this.$el.clientHeight;
          this.start = 0;
          this.end = this.start + this.visibleCount;
          // 置顶
          this.$refs.list.scrollTop = 0;
      }
  },
  props: {
    //所有列表数据
    listData: {
      type: Array,
      default: () => []
    },
    //每项高度
    itemSize: {
      type: Number,
      default: 200
    },
    tabType: {
      type: String,
      default: () => ''
    }
  },
  computed: {
    //列表总高度
    listHeight() {
      return this.listData.length * this.itemSize;
    },
    //可显示的列表项数
    visibleCount() {
      return Math.ceil(this.screenHeight / this.itemSize)
    },
    //偏移量对应的style
    getTransform() {
      return `translate3d(0,${this.startOffset}px,0)`;
    },
    //获取真实显示列表数据
    visibleData() {
      return this.listData.slice(this.start, Math.min(this.end, this.listData.length));
    },
    listDataWatch() {
      return JSON.parse(JSON.stringify(this.listData))
    },
    tabTypeWatch() {
      return JSON.parse(JSON.stringify(this.tabType))
    },
  },
  mounted() {
    this.zeroLength();
  },
   .infinite-list-container {
    height: 100%;
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
  }

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

  .infinite-list {
    left: 0;
    right: 0;
    top: 0;
    position: absolute;
    /* text-align: center; */
  }

  .infinite-list-item {
    padding: 10px;
    margin: 10px 10px 10px 5px;
    color: #fff;
    box-sizing: border-box;
    border: 1px solid #fff;
    border-radius: 10px;
    background: rgba(51, 64, 84);
  }