列表虚拟滚动

父组件

<template>
  <div>
    <virtuaList :listData="list" :itemHeight="20" :visibleCount="30" />
  </div>
</template>

<script>
import virtuaList from './components/virtuaList.vue';
export default {
  name: "App",
  components: {
    virtuaList
  },
  data() {
    return {
      list:[]
    };
  },
  mounted() {
    // 默认数据
    for (let i = 1; i < 10000; i++) {
      this.list.push(i);
    }
  },
  methods: {}
};
</script>

子组件

<template>
    <!--虚拟滚动-->
    <div :style="{ height: itemHeight * visibleCount + 'px' }" ref="scrollContainer" class="scrollContainer">
        <div :style="{ height:itemHeight * listData.length + 'px'}" class="scrollContent">

        </div>
        <div ref="listContainer" class="listContainer">
            <div v-for="item of slicesList" :style="{ height: itemHeight + 'px' }"  :key="item">{{item}}</div>
        </div>
    </div>
</template>

<script>
export default {
  name: 'VirtuaList',
  props:
 {
    listData: {
      type: Array,
      default: () => [],
    },
    itemHeight:{
      type: Number,
      default: 20,
    },
    visibleCount:
    {
      type: Number,
      default: 20,
    },
  },
  data() {
    return {
      // 虚拟列表
      start: 0, // 截取开始
      end: 0, // 截取结束
    };
  },
  computed:{
    slicesList(){
      return this.listData.slice(this.start,this.end);
    }
  },
  mounted() {
    // 结束位置等于可视区域数量
    this.end = this.visibleCount;
    this.$refs.scrollContainer.addEventListener('scroll', this.handleScroll);
  },
  methods: {
    handleScroll() {
      // 获取滚动条位置
      const scrollTop = this.$refs.scrollContainer.scrollTop;
      // 计算开始位置
      this.start = Math.floor(scrollTop / this.itemHeight);
      // 计算结束位置
      this.end = this.start + this.visibleCount;
        
      // 设置列表容器位置
      this.$refs.listContainer.style.transform = `translateY(${this.start * this.itemHeight}px)`;
    },
  },
  beforeDestroy() {
    this.$refs.scrollContainer.removeEventListener('scroll', this.handleScroll);
  }
};
</script>

<style lang="css" scoped>
    .scrollContainer{
        width: 300px;
        background-color: aquamarine;
        position: relative;
        margin: 0 auto;
        overflow-y: scroll;
    }
    .scrollContent{
        /* 滚动条 */
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
    }
</style>

### Vue 中实现列表虚拟滚动的方法 在处理大型数据集时,传统的 DOM 列表渲染方式可能会导致性能瓶颈。通过使用 **虚拟滚动** 技术,可以显著减少页面中的 DOM 节点数量,从而提升应用的响应速度和用户体验。 以下是基于 Vue虚拟滚动技术的一个简单示例: #### 1. 安装依赖库 为了简化开发过程,可以选择现有的虚拟滚动库 `vue-virtual-scroller` 或其他类似的工具来快速实现功能[^1]。如果希望手动实现,则可以通过自定义逻辑完成。 安装 `vue-virtual-scroller`: ```bash npm install vue-virtual-scroller --save ``` #### 2. 基本代码结构 以下是一个简单的例子,展示了如何利用 `RecycleScroller` 组件(来自 `vue-virtual-scroller` 库)创建一个高性能的虚拟滚动列表[^2]。 ```html <template> <div class="virtual-list-container"> <!-- RecycleScroller 提供高效的虚拟化能力 --> <recycle-scroller class="scroller" :items="listData" :item-size="50" <!-- 每个条目的高度 --> key-field="id" v-slot="{ item }" > <div class="item">{{ item.name }}</div> <!-- 自定义每一项的内容 --> </recycle-scroller> </div> </template> <script> import { RecycleScroller } from 'vue-virtual-scroller'; import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'; // 导入样式文件 export default { components: { RecycleScroller, }, data() { return { listData: [], // 数据源 }; }, created() { this.listData = Array.from({ length: 1000 }, (_, i) => ({ id: i + 1, name: `Item ${i + 1}`, })); }, }; </script> <style scoped> .virtual-list-container { height: 400px; /* 设置容器的高度 */ } .scroller .item { height: 50px; line-height: 50px; text-align: center; border-bottom: 1px solid #ccc; } </style> ``` 上述代码实现了以下几点: - 使用 `RecycleScroller` 来管理大列表的显示。 - 配置每一条目固定高度为 50px,并绑定动态生成的数据源。 - 用户仅能看到当前可视区域内的内容,其余部分会被自动卸载以节省资源[^3]。 #### 3. 手动实现虚拟滚动的核心逻辑 如果不借助第三方库,也可以自己编写核心算法。主要涉及以下几个方面: - 计算可视区域内应展示的起始索引和结束索引。 - 动态调整偏移量以匹配用户的实际滚动位置。 - 确保每次重新计算后的 DOM 结构能够无缝衔接上一次的状态。 下面是一份基础的手写版本伪代码作为参考: ```javascript computedVisibleItems(scrollTop, containerHeight, itemHeight) { const startIdx = Math.floor(scrollTop / itemHeight); const endIdx = startIdx + Math.ceil(containerHeight / itemHeight); return { startIndex: startIdx, endIndex: endIdx, }; } methods: { handleScroll(event) { const scrollTop = event.target.scrollTop; const visibleRange = this.computedVisibleItems( scrollTop, this.$refs.container.clientHeight, this.itemSize ); this.startIndex = visibleRange.startIndex; this.endIndex = visibleRange.endIndex; } }, ``` 此方法允许开发者完全掌控细节,但也增加了复杂度和调试难度。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最初的M

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值