所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

vue-virtual-scroller 虚拟滚动库 – 轻松处理10万+数据,性能提升90%

📖 简介

vue-virtual-scroller 是一个专为 Vue.js 应用设计的高性能虚拟滚动组件库。它通过”虚拟化”技术解决了在 Vue 应用中渲染大量数据时的性能问题,只渲染用户当前可见的元素,而不是整个列表,从而显著提高了渲染性能和内存使用效率。

🎯 核心特性

  • 🚀 极致性能:只渲染可视区域内的元素,支持数万条数据的流畅滚动
  • 💾 内存优化:显著降低 DOM 节点数量,减少内存占用
  • 🎨 高度定制:灵活的样式和交互定制能力
  • 📱 响应式:完美适配各种屏幕尺寸
  • 🔄 动态高度:支持固定高度和动态高度两种模式
  • ⚡ 平滑滚动:优化的滚动体验,支持自动滚动到指定位置
  • 🔧 易于集成:简单的 API 设计,快速上手

🆚 与其他虚拟滚动库对比

特性vue-virtual-scrollerreact-windowreact-virtualized
框架支持Vue 2/3ReactReact
体积轻量级轻量级较重
API 简洁性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
性能表现优秀优秀优秀
文档完整性完整完整完整

📦 安装

使用 npm

npm install vue-virtual-scroller@next

🚀 快速开始

基础用法

<template>
  <div class="virtual-list-container">
    <RecycleScroller
      class="scroller"
      :items="items"
      :item-size="50"
      key-field="id"
    >
      <template #default="{ item }">
        <div class="list-item">
          {{ item.name }}
        </div>
      </template>
    </RecycleScroller>
  </div>
</template>

<script>
import { RecycleScroller } from "vue-virtual-scroller";
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";

export default {
  name: "VirtualListExample",
  components: {
    RecycleScroller,
  },
  data() {
    return {
      items: Array.from({ length: 10000 }, (_, index) => ({
        id: index,
        name: `Item ${index}`,
      })),
    };
  },
};
</script>

<style scoped>
.virtual-list-container {
  height: 400px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  overflow: hidden;
}

.scroller {
  height: 100%;
}

.list-item {
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
  background: white;
  transition: background-color 0.2s;
}

.list-item:hover {
  background-color: #f5f5f5;
}
</style>

🎨 组件详解

RecycleScroller

RecycleScroller 是主要的虚拟滚动组件,适用于固定高度的列表项。

Props

属性名类型默认值说明
itemsArray[]要渲染的数据数组
itemSizeNumber50每个列表项的高度(像素)
keyFieldString‘id’用于唯一标识每个项目的字段名
pageModeBooleanfalse是否启用页面模式
prerenderNumber5预渲染的项目数量
bufferNumber200缓冲区大小(像素)
minItemSizeNumber最小项目高度
sizeFieldString动态高度字段名
typeFieldString项目类型字段名

Events

事件名参数说明
scroll{ event, scrollTop, scrollLeft }滚动事件
resize{ size }容器大小变化事件
visible{ startIndex, endIndex }可见项目变化事件

DynamicScroller

DynamicScroller 适用于动态高度的列表项。

<template>
  <div class="dynamic-list-container">
    <DynamicScroller
      class="scroller"
      :items="items"
      :min-item-size="50"
      key-field="id"
    >
      <template #default="{ item, index, active }">
        <DynamicScrollerItem
          :item="item"
          :active="active"
          :size-dependencies="[item.content]"
          :watch-data="true"
        >
          <div class="dynamic-item">
            <h3>{{ item.title }}</h3>
            <p>{{ item.content }}</p>
          </div>
        </DynamicScrollerItem>
      </template>
    </DynamicScroller>
  </div>
</template>

<script>
import { DynamicScroller, DynamicScrollerItem } from "vue-virtual-scroller";
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";

export default {
  name: "DynamicListExample",
  components: {
    DynamicScroller,
    DynamicScrollerItem,
  },
  data() {
    return {
      items: Array.from({ length: 1000 }, (_, index) => ({
        id: index,
        title: `Item ${index}`,
        content: `This is the content for item ${index}. ${"Lorem ipsum ".repeat(
          Math.floor(Math.random() * 10) + 1
        )}`,
      })),
    };
  },
};
</script>

<style scoped>
.dynamic-list-container {
  height: 500px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  overflow: hidden;
}

.scroller {
  height: 100%;
}

.dynamic-item {
  padding: 16px;
  border-bottom: 1px solid #f0f0f0;
  background: white;
}

.dynamic-item h3 {
  margin: 0 0 8px 0;
  color: #333;
  font-size: 16px;
  font-weight: 600;
}

.dynamic-item p {
  margin: 0;
  color: #666;
  line-height: 1.5;
}
</style>

🔧 高级用法

带选择功能的虚拟列表

<template>
  <div class="selectable-list">
    <div class="list-header">
      <div class="selection-info">已选择 {{ selectedItems.length }} 个项目</div>
      <button @click="selectAll" class="btn btn-primary">全选</button>
      <button @click="clearSelection" class="btn btn-secondary">清除</button>
      <button @click="scrollToBottom" class="btn btn-info">滚动到底部</button>
    </div>

    <RecycleScroller
      ref="scroller"
      class="scroller"
      :items="items"
      :item-size="50"
      key-field="id"
    >
      <template #default="{ item }">
        <div
          class="list-item"
          :class="{ selected: selectedItems.includes(item.id) }"
          @click="toggleSelection(item.id)"
        >
          <input
            type="checkbox"
            :checked="selectedItems.includes(item.id)"
            @change="toggleSelection(item.id)"
            @click.stop
            class="checkbox"
          />
          <span class="item-name">{{ item.name }}</span>
          <span class="item-status">{{ item.status }}</span>
        </div>
      </template>
    </RecycleScroller>
  </div>
</template>

<script>
import { RecycleScroller } from "vue-virtual-scroller";
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";

export default {
  name: "SelectableListExample",
  components: {
    RecycleScroller,
  },
  data() {
    return {
      selectedItems: [],
      items: Array.from({ length: 5000 }, (_, index) => ({
        id: index,
        name: `Item ${index}`,
        status:
          index % 3 === 0 ? "活跃" : index % 3 === 1 ? "待处理" : "已完成",
      })),
    };
  },
  methods: {
    toggleSelection(id) {
      const index = this.selectedItems.indexOf(id);
      if (index > -1) {
        this.selectedItems.splice(index, 1);
      } else {
        this.selectedItems.push(id);
      }
    },
    selectAll() {
      this.selectedItems = this.items.map((item) => item.id);
    },
    clearSelection() {
      this.selectedItems = [];
    },
    scrollToBottom() {
      // 滚动到最后一个项目
      this.$nextTick(() => {
        if (this.$refs.scroller) {
          this.$refs.scroller.scrollToItem(this.items.length - 1);
        }
      });
    },
  },
};
</script>

<style scoped>
.selectable-list {
  height: 500px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.list-header {
  padding: 12px 16px;
  background: #f8f9fa;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  align-items: center;
  gap: 12px;
}

.selection-info {
  flex: 1;
  font-size: 14px;
  color: #666;
}

.btn {
  padding: 6px 12px;
  border: none;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.btn-primary {
  background: #007bff;
  color: white;
}

.btn-primary:hover {
  background: #0056b3;
}

.btn-secondary {
  background: #6c757d;
  color: white;
}

.btn-secondary:hover {
  background: #545b62;
}

.btn-info {
  background: #17a2b8;
  color: white;
}

.btn-info:hover {
  background: #138496;
}

.scroller {
  flex: 1;
}

.list-item {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
  background: white;
  cursor: pointer;
  transition: background-color 0.2s;
}

.list-item:hover {
  background-color: #f5f5f5;
}

.list-item.selected {
  background-color: #e3f2fd;
}

.checkbox {
  margin-right: 12px;
}

.item-name {
  flex: 1;
  font-weight: 500;
  color: #333;
}

.item-status {
  font-size: 12px;
  padding: 2px 6px;
  border-radius: 3px;
  background: #f0f0f0;
  color: #666;
}
</style>

🎯 性能优化技巧

1. 使用 key 属性

确保每个列表项都有唯一的 key,这对于虚拟滚动的性能至关重要:

<RecycleScroller
  :items="items"
  :item-size="50"
  key-field="id"
/>

2. 避免在模板中使用复杂计算

<!-- ❌ 错误做法 -->
<template #default="{ item }">
  <div>{{ expensiveComputation(item) }}</div>
</template>

<!-- ✅ 正确做法 -->
<template #default="{ item }">
  <div>{{ item.computedValue }}</div>
</template>

<script>
export default {
  computed: {
    items() {
      return this.rawItems.map((item) => ({
        ...item,
        computedValue: this.expensiveComputation(item),
      }));
    },
  },
};
</script>

3. 使用 v-memo 优化渲染

<template #default="{ item }">
  <div v-memo="[item.id, item.name]">
    {{ item.name }}
  </div>
</template>

4. 合理设置缓冲区大小

<RecycleScroller
    :items="items"
    :item-size="50"
    :buffer="300"
    key-field="id"
/>

5. 滑动到底部

scrollToBottom() {
  // 滚动到最后一个项目
  this.$nextTick(() => {
    if (this.$refs.scroller) {
      this.$refs.scroller.scrollToItem(this.items.length - 1);
    }
  });
}

🐛 常见问题

Q: 列表项高度不一致怎么办?

A: 使用 DynamicScroller 组件:

<DynamicScroller :items="items" :min-item-size="50" key-field="id">
  <template #default="{ item, index, active }">
    <DynamicScrollerItem
      :item="item"
      :active="active"
      :size-dependencies="[item.content]"
    >
      <div class="dynamic-item">
        {{ item.content }}
      </div>
    </DynamicScrollerItem>
  </template>
</DynamicScroller>

资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/945,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?