这段时间写了一个 vue 的滚动组件: starkwang/vue-virtual-collection, 现在正式宣传一下~
类似的 vue 列表滚动组件已经有好几个了, 但一直没有针对瀑布流的 vue 滚动组件, 也就是类似这样的滚动组件:
点击下面可以直接看 demo :
vue-virtual-collectionstarkwang.github.io
欢迎任何形式的 PRIssue ~
使用
用起来非常简单:
- import Vue from 'vue'
- import VirtualCollection from 'vue-virtual-collection'
- Vue.use(VirtualCollection)
然后就可以在你的代码中使用了, 下面是一个简单的例子:
- <template>
- <div>
- <VirtualCollection :cellSizeAndPositionGetter="cellSizeAndPositionGetter" :collection="items" :height="500" :width="330">
- <div slot="cell" slot-scope="props">{{props.data}}</div>
- </VirtualCollection>
- </div>
- </template>
- <script>
- export default {
- data () {
- return {
- /**
- * This will create 1000 items like:
- * [
- * { data: '#0' },
- * { data: '#1' },
- * ...
- * { data: '#999' }
- * ]
- */
- items: new Array(1000).fill(0).map((_, index) => ({ data: '#' + index }))
- }
- },
- methods: {
- cellSizeAndPositionGetter(item, index) {
- // compute size and position
- return {
- width: 100,
- height: 150,
- x: (index % 2) * 110,
- y: parseInt(index / 2) * 160
- }
- }
- }
- }
- </script>
实现
现在自测大概可以无卡顿支持 100W+ 的数据渲染, 大部分场景下肯定是够用了原理上就是局部渲染和 DOM 回收, 不会渲染全部数据, 而是把当前 viewport 中展示的 Cell 渲染出来, 所以性能上比渲染全量数据要快太多了
用代码简略表示一下就是:
const DisplayCells = Cells.filter(isInViewPort)
但这样实现的话会有问题, 如果遍历所有数据一个一个去计算 isInViewPort, 在数据很多很多的时候, 性能非常差 (然而现在大部分 infinite scroll 组件都是这么做的 = =)
为了高效率地 viewport 中有哪些 Cell 需要渲染, 我们需要改用块渲染的思想我们可以定义一个块为 200 * 200 的正方形, 所有与这个块有重叠的 Cell 都会在这个块中记录下来
这些块被保存在一个 Map 中, 当滚动发生时, 我们只需要计算当前该展示哪些块的数据, 然后去这些块中找到对应的 Cell 就可以了, 而不需要去遍历所有的 Cell
下面是一个画出来的例子:
此时, Map 中记录的应该是:
- {
- "0.0": [1, 2, 3, 5], // 0.0 块与 1,2,3,5 号 Cell 有重叠, 下同
- "0.1": [5, 3, 6, 7],
- "0.2": [7, 6, 8, 9],
- "1.0": [2, 3, 4],
- "1.1": [3, 4, 6],
- "1.2": [6, 9]
- }
当我们滚动了页面, 根据滚动的距离 viewPort 的宽高, 可以很容易计算出当前需要渲染哪些块
比如上面这个例子中, 我们需要渲染 0.00.11.01.1 这四个块, 然后我们只需要去 Map 中找到这些块包含的 Cell, 就可以高效率地渲染了, 而不是去遍历所有的 Cell 暴力搜索
这也是另一个十分流行的开源组件 react-virtualize 的核心思想, 可以在下面看具体的 SectionManager 是如何实现的:
https://github.com/bvaughn/react-virtualized/blob/master/source/Collection/SectionManager.jsgithub.com
类似的思想同样可以用到列表表格格栅系统上
来源: https://juejin.im/entry/5aa2464bf265da2373140b60