vue2 长列表+虚拟dom

<template>
  <div class="virtual-list" ref="container" @scroll="handleScroll">
    <!-- 占位元素,用于撑开滚动区域 -->
    <div class="list-phantom" :style="{ height: totalHeight + 'px' }"></div>

    <!-- 实际渲染的列表内容 -->
    <div class="list-content" :style="{ transform: `translateY(${offset}px)` }">
      <div
        v-for="item in visibleData"
        :key="item.id"
        class="list-item"
        :style="{ height: itemHeight + 'px' }"
      >
        {{ item.content }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: [], // 所有数据
      visibleData: [], // 当前可见的数据
      itemHeight: 50, // 每项高度
      screenHeight: 0, // 可视区域高度
      startIndex: 0, // 可见区域的起始索引
      endIndex: 0, // 可见区域的结束索引
      offset: 0 // 列表的偏移量
    };
  },
  computed: {
    // 列表总高度
    totalHeight() {
      return this.data.length * this.itemHeight;
    }
  },
  mounted() {
    this.screenHeight = this.$refs.container.offsetHeight; // 获取可视区域高度
    this.loadData(); // 初始加载数据
    this.updateVisibleData(); // 初始渲染可见数据
  },
  methods: {
    // 模拟分段加载数据
    loadData() {
      // 假设每次加载 100 条数据
      setTimeout(() => {
        const newData = Array.from({ length: 100 }, (_, i) => ({
          id: this.data.length + i + 1,
          content: `Item ${this.data.length + i + 1}`
        }));
        this.data = this.data.concat(newData);
        console.log(this.data);
        this.updateVisibleData(); // 初始渲染可见数据
      }, 100);
    },
    // 更新可见区域的数据
    updateVisibleData() {
      const startIndex = Math.floor(this.offset / this.itemHeight); // 起始索引
      const endIndex = Math.min(
        startIndex + Math.ceil(this.screenHeight / this.itemHeight),
        this.data.length
      ); // 结束索引
      this.startIndex = startIndex;
      this.endIndex = endIndex;
      this.visibleData = this.data.slice(startIndex, endIndex);
    },
    // 处理滚动事件
    handleScroll() {
      const scrollTop = this.$refs.container.scrollTop; // 获取滚动距离
      console.log(this.$el);
      this.offset = scrollTop; // 更新偏移量
      this.updateVisibleData(); // 更新可见数据

      // 如果滚动到底部,加载更多数据
      if (scrollTop + this.screenHeight >= this.totalHeight) {
        console.log(1);
        this.loadData();
      }
    }
  }
};
</script>

<style>
.virtual-list {
  height: 100vh; /* 可视区域高度 */
  overflow-y: auto; /* 允许垂直滚动 */
  position: relative;
}

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

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

.list-item {
  display: flex;
  align-items: center;
  padding: 10px;
  box-sizing: border-box;
  border-bottom: 1px solid #eee;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值