虚拟列表(VirtualList)在Taro3中的使用

技术概述

虚拟列表(VirtualList)是一种在展示大量数据(长列表)时使用的插件,通过只显示必要的DOM和无限滚动,提升页面的性能。在web环境中,我们可以使用vue-virtual-scroll-list之类的npm包。最近热门的小程序框架Taro3也提供了这个能力。从文档说明上看,其功能算是vue-virtual-scroll-list的一个子集。

技术详述

在Taro中使用VirtualList非常简单,我们以Vue.js模式的项目为例——

这里是一个单词列表页面,需要展示数千个单词及中文,如果直接展示,页面的将会卡顿较长时间(团队成员也提出了这一点见issue),因此经过考虑我们选用了VirtualList作为解决方案,几乎不再会卡顿。以下是精简后的代码。
完整代码点此:Zhai-dict

1. 引入必要文件

// app.js 入口文件
import VirtualList from `@tarojs/components/virtual-list`

Vue.use(VirtualList)

2. 编写单项组件,用于长列表单个项目的展示

<! –– ListItem.vue 单项组件 ––> 
<template>
  <!-- 这里的style=css是一定要加的 -->
  <view class="word-wrapper" :style="css">
    <view class="word">{{ data[index].word }}</view>
    <view class="translation">{{ data[index].translation }}</view>
  </view>
</template>

<script>
export default {
  name: 'ListItem',
  props: ['index', 'data', 'css']
}
</script>

<style lang="scss">
.word-wrapper {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  padding: 30px 20px;
  background: #f7f7f7;
  border-bottom: 1px solid #dddddd;
...
}

传入该组件的props有以下4个属性:

  • css: 单项的样式,样式必须传入组件的 style 中
  • data: 组件渲染的数据,即virtualList的itemData属性
  • index: 组件渲染数据的索引
  • isScrolling: 组件是否正在滚动,当 useIsScrolling 值为 true 时返回布尔值,否则返回 undefined

通过这些属性可以渲染出单个的组件。

3. 编写长列表页面组件

<! –– History.vue 页面组件 ––> 
<template>
  <view id="pHistory">
    <virtual-list
      :height="listHeight"
      :item-data="wordList"
      :item-count="wordList.length"
      :item-size="75"
      :item="ListItem"
      width="100%"
      v-if="wordList.length"
      :overscanCount="20"
    />
    <view class="empty" v-show="wordList.length === 0">- 暂无内容 -</view>
  </view>
</template>

<script>
import Taro from '@tarojs/taro'
import ListItem from './components/ListItem.vue'

export default {
  name: 'pageHistory',
  data() {
    return {
      pageState: 1,
      wordList: [],
      ListItem
    }
  },
  computed: {
    listHeight() {
      return Taro.getSystemInfoSync().windowHeight - 50
    }
  },
}
</script>

virtualList的常用属性如下:

  • item: VueComponent
    将要渲染的列表单项组件,传入的props如上文所述。
  • itemCount: number
    列表的长度。必填。
  • itemData: Array
    渲染数据。必填。
  • itemSize: number
    列表单项的大小,垂直滚动时为高度,水平滚动时为宽度。必填。
  • height: number | string
    列表的高度。当滚动方向为垂直时必填。
  • width: number | string
    列表的宽度。当滚动方向为水平时必填。
  • overscanCount: number = 1
    在可视区域之外渲染的列表单项数量,值设置得越高,快速滚动时出现白屏的概率就越小,相应地,每次滚动的性能会变得越差。

注意事项&最佳实践

  1. 单项组件中,根元素一定要加上:style="css",哪怕你没有传入自定义的css。没有加上会导致滚动之后页面显示不完全。
  2. height属性一定要是一个固定值,不能是百分比或vh/vw等。可以在computed里面进行一系列处理,如History.vue32行。
  3. 由于小程序的性能稍差,建议overscanCount设一个稍大的值,可能会有较好的展示效果。当然,过大的值也会产生反效果,这需要开发者进行一定尝试。

总结

本例的数据是从本地读取,因此也无需使用“无限滚动”的方案。虚拟列表组件和分页都是大量数据场景下提升性能的有效解决方案,在实际使用中有较大的意义。
从原理来看,这些组件都是通过计算好列表的长度,在wrapper处加上合适的padding-top和padding-bottom撑起这个列表,同时通过IntersectionObserver等方式判断组件是否进入/离开了视口,并且只保留距离视口一定范围内的DOM元素。随着用户滚动不断更新展示的组件,这样就在用户无感的情况下做到了对超长列表的部分展示。

参考文档

https://github.com/tangbc/vue-virtual-scroll-list
https://nervjs.github.io/taro/docs/next/virtual-list/#itemcount-number-1

posted @ 2020-06-25 21:36  ldc-37  阅读(880)  评论(0编辑  收藏