使用三方工具实现虚拟列表

前言

书接上文,前篇文章介绍了如何手写一个虚拟列表,这篇文章就介绍一下如何偷懒使用现有的三方工具实现

传送门:如果让你渲染十万条数据,无脑全部渲染?拖出去斩了

vueUse方案实现:

采用vueUse中的useVirtualList方法同样可以实现虚拟列表(相当于是使用一个封装好的方法)

文档链接

步骤:

  1. 装包

npm i @vueuse/core

  1. 导入useVirtualList方法
xml 复制代码
<script setup lang="ts">
import { useVirtualList } from '@vueuse/core'
</script>

如何使用?

在使用useVirtualList方法时需要传入两个参数,一个是数据源(就是你那十万条数据),一个是配置项(配置每项的高度)

在配置项中配置的高度一定要和模板中渲染的每一项的高度相同(即配置项的高度要与css中的高度保持一致)

这个方法返回三个字段,一个处理后的数据源,两个依赖项,这两个依赖项需要绑定到视图区域和占位盒子身上,从而实现虚拟列表的效果

手动添加类名,然后审查元素:

xml 复制代码
<template>
  <div v-bind="containerProps" style="height: 500px" class="container">
    <div v-bind="wrapperProps" class="slot">
      <div v-for="item in list" :key="item.data.id" style="height: 40px">
        Row: {{ item.data }}
      </div>
    </div>
  </div>
</template>

大致的效果就是虚拟列表的div包裹着占位的div,占位的div内进行渲染。当然,样式自己就根据需要添加即可

完整代码:

typescript 复制代码
<script setup lang="ts">
import { useVirtualList } from '@vueuse/core'
import { onMounted, ref } from 'vue'
type Item = {
  id: number
  name: string
}

// 所有的数据,比如这个数组存放了十万条数据
const allListData = ref<Item[]>([])
// 获取十万条数据
const getData = () => {
  for (let i = 0; i < 10000; i++) {
    allListData.value.push({ name: `第${i}条数据`, id: i })
  }
}

onMounted(() => {
  getData()
})

const { list, containerProps, wrapperProps } = useVirtualList(allListData, {
  // 此处配置的高度一定要和31行渲染时每一行的高度相同
  itemHeight: 40
})
</script>

<template>
  <div v-bind="containerProps" style="height: 500px" class="container">
    <div v-bind="wrapperProps" class="slot">
      <div v-for="item in list" :key="item.data.id" style="height: 40px">
        Row: {{ item.data }}
      </div>
    </div>
  </div>
</template>
  
<style scoped lang="scss">
.container {
  border: 1px solid black;
}
</style>

同时注意,将原始数据源传给useVirtualList之后返回的list是经过封装过的,想这里原本数据的每一项的结构是{ name:'', id:xx },经过处理后,再想访问name或者id,就得多访问一层data,即list.data.name / list.data.id

完整代码:

typescript 复制代码
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'

type Item = {
  id: number
  name: string
}

// 所有的数据,比如这个数组存放了十万条数据
const allListData = ref<Item[]>([])
// 获取十万条数据
const getData = () => {
  for (let i = 0; i < 10000; i++) {
    allListData.value.push({ name: `第${i}条数据`, id: i })
  }
}

onMounted(() => {
  getData()
})

// 每一项的高度,比如 40 像素
const itemHeight = ref(40)
</script>

<template>
  <RecycleScroller
    class="viewport"
    :items="allListData"
    :item-size="itemHeight"
    key-field="id"
    v-slot="{ item }"
    item-class="item"
  >
    {{ item.name }}
  </RecycleScroller>
</template>

<style scoped lang="scss">
.viewport {
  box-sizing: border-box;
  width: 240px;
  height: 400px;
  border: solid 1px #000000;
  // 开启滚动条
  overflow-y: auto;

  <!-- 由于模板中使用了 item-class 属性将渲染的每一项的类名改为 item,所以这里开启深层次的样式修改-->
  :deep(.item) {
    box-sizing: border-box;
    width: 100%;
    height: 40px;		// 高度设置得和 item-size 属性的值一致。表示每一项的高度
    display: flex;
    justify-content: center;
    align-items: center;
    // 隔行变色
    &:nth-child(even) {
      background: skyblue;
    }
    &:nth-child(odd) {
      background: red;
    }
  }
}
</style>

实现效果:

审查一下元素:

其实可以发现底层实现原理和之前手写的部分差不多,都是最外层一个虚拟列表盒子,内层放置一个具有所有数据的高度的盒子,然后再设置一个视图层进行滚动。但是使用封装好的东西可以不用自己设置定位以及更新top值,而且其实它的文档里还有其他很多的属性和事件,拓展性强。还支持每一项的高度可以不同(可能在那种评论区用得多,毕竟每条评论的内容不一定都相同)

报错问题:

由于使用的是 Vue3 + TS,所以在导入的时候会有类型报错,虽然不影响功能

尝试下载提示中的包文件,但是竟然显示找不到了,可能是在@types中没有这个包的声明文件吧

相关推荐
别拿曾经看以后~1 小时前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
我要洋人死1 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人1 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人1 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9152 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼3 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍