长列表渲染(虚拟列表)
在典型的 Taro 应用中,正常的列表渲染遵循以下的逻辑:
- 生成或从远程加载数据
- 把数据加入框架的响应式数据中
- 框架使用 diff 算法或其它机制根据数据的不同尝试全量更新视图
- Taro 运行时捕获框架的更新请求更新视图
如果按照此逻辑,当第一步我们生成或加载的数据量非常大时就可能会产生严重的性能问题,导致视图无法响应操作一段时间。为了解决这个问题,我们可以采用另一种方式:比起全量渲染数据生成的视图,可以只渲染当前可视区域(visible viewport)的视图,非可视区域的视图在用户滚动到可视区域再渲染:
#
React/Nerv使用 React/Nerv 我们可以直接从 @tarojs/components/virtual-list
引入虚拟列表(VirtualList)组件:
一个最简单的长列表组件会像这样,VirtualList
的 5 个属性都是必填项:
#
无限滚动实现无限滚动也非常简单,我们只需要在列表滚动到底部时,往列表尾部追加数据即可:
#
propschildren: ReactComponent
#
将要渲染的列表单项组件。组件的 props
有 4 个属性:
style
: 单项的样式,样式必须传入组件的style
中data
: 组件渲染的数据,同虚拟列表itemData
index
: 组件渲染数据的索引isScrolling
: 组件是否正在滚动,当useIsScrolling
值为true
时返回布尔值,否则返回undefined
推荐使用 React.memo
或 React.PureComponent
或使用 shouldComponentUpdate()
来优化此组件,避免不必要的渲染。
itemCount: number
#
列表的长度。必填。
itemData: Array<any>
#
渲染数据。必填。
itemSize: number
#
列表单项的大小,垂直滚动时为高度,水平滚动时为宽度。必填。
height: number | string
#
列表的高度。当滚动方向为垂直时必填。
width: number | string
#
列表的宽度。当滚动方向为水平时必填。
className: string
#
根组件 CSS 类
style: Style
#
根组件的样式
initialScrollOffset: number = 0
#
初始滚动偏移值,水平滚动影响 scrollLeft
,垂直滚动影响 scrollTop
。
innerElementType: ReactElement = View
#
列表内部容器组件类型,默认值为 View
。此容器的 parentNode
是 ScrollView
,childNodes
是列表。
innerRef: Ref | Function
#
列表内部容器组件的 ref。
layout: string = 'vertical'
#
滚动方向。vertical
为垂直滚动,horizontal
为平行滚动。默认为 vertical
。
onScroll: Function
#
列表滚动时调用函数,函数的第一个参数为对象,由三个属性构成:
scrollDirection
,滚动方向,可能值为forward
往前,backward
往后。scrollOffset
,滚动距离scrollUpdateWasRequested
, 当滚动是由scrollTo()
或scrollToItem()
调用时返回true
,否则返回false
onScrollNative: Function
#
调用平台原生的滚动监听函数。
overscanCount: number = 1
#
在可视区域之外渲染的列表单项数量,值设置得越高,快速滚动时出现白屏的概率就越小,相应地,每次滚动的性能会变得越差。
unlimitedSize?: boolean
#
解开高度列表单项大小限制,默认值使用: itemSize (请注意,初始高度与实际高度差异过大会导致隐患)。
position?: 'absolute' | 'relative'
#
布局方式,默认采用 "absolute"
renderBottom?: ReactNode
#
底部区域
useIsScrolling: boolean
#
是否注入 isScrolling
属性到 children
组件。这个参数一般用于实现滚动骨架屏(或其它 placeholder) 时比较有用。
ScrollView
组件的参数#
其它 除了以上参数,所有 ScrollView
组件的参数都可以传入 VirtualList
组件,冲突时优先使用以上文档描述的参数。
#
方法通过 React.createRef()
创建 ref,挂载到 VirtualList
上可以访问到 VirtualList
的内部方法:
scrollTo(scrollOffset: number): void
#
滚动到指定的地点。
scrollToItem(index: number, align: string = "auto"): void
#
滚动到指定的条目。
第二参数 align
的值可能为:
auto
: 尽可能滚动距离最小保证条目在可视区域中,如果已经在可视区域,就不滚动smart
: 条目如果已经在可视区域,就不滚动;如果有部分在可视区域,尽可能滚动距离最小保证条目在可视区域中;如果条目完全不在可视区域,那就滚动到条目在可视区域居中显示center
: 让条目在可视区域居中显示end
: 让条目在可视区域末尾显示start
: 让条目在可视区域末尾显示
#
Vue在 Vue 中使用虚拟列表,我们需要在入口文件声明使用:
一个最简单的长列表组件会像这样,virtual-list
的 5 个属性都是必填项:
#
无限滚动实现无限滚动也非常简单,我们只需要在列表滚动到底部时,往列表尾部追加数据即可:
#
propsitem: VueComponent
#
将要渲染的列表单项组件。组件的 props
有 4 个属性:
css
: 单项的样式,样式必须传入组件的style
中data
: 组件渲染的数据,同虚拟列表itemData
index
: 组件渲染数据的索引isScrolling
: 组件是否正在滚动,当useIsScrolling
值为true
时返回布尔值,否则返回undefined
itemCount: number
#
列表的长度。必填。
itemData: Array<any>
#
渲染数据。必填。
itemSize: number
#
列表单项的大小,垂直滚动时为高度,水平滚动时为宽度。必填。
height: number | string
#
列表的高度。当滚动方向为垂直时必填。
width: number | string
#
列表的宽度。当滚动方向为水平时必填。
wclass: string
#
根组件 CSS 类
wstyle: Style
#
根组件的样式
initialScrollOffset: number = 0
#
初始滚动偏移值,水平滚动影响 scrollLeft
,垂直滚动影响 scrollTop
。
innerElementType: string = 'view'
#
列表内部容器组件类型,默认值为 view
。此容器的 parentNode
是 scroll-view
,childNodes
是列表。
layout: string = 'vertical'
#
滚动方向。vertical
为垂直滚动,horizontal
为平行滚动。默认为 vertical
。
v-on:scroll: Function
#
列表滚动时调用函数,函数的第一个参数为对象,由三个属性构成:
scrollDirection
,滚动方向,可能值为forward
往前,backward
往后。scrollOffset
,滚动距离scrollUpdateWasRequested
, 当滚动是由scrollTo()
或scrollToItem()
调用时返回true
,否则返回false
scrollNative: Function
#
调用平台原生的滚动监听函数。注意调用传递此函数时使用的是 v-bind
而不是 v-on
:
overscanCount: number = 1
#
在可视区域之外渲染的列表单项数量,值设置得越高,快速滚动时出现白屏的概率就越小,相应地,每次滚动的性能会变得越差。
useIsScrolling: boolean
#
是否注入 isScrolling
属性到 item
组件。这个参数一般用于实现滚动骨架屏(或其它 placeholder) 时比较有用。