废话(不是): 项目是一个移动端的社区,可以发帖,可发布文字+图片(最多9张),之前直接搭的页面,通过分页加载数据,一次请求10条。后来产品那边反映在ios端会出现发热严重和掉电的情况。(部分原因: 社区首页是一直有兜底数据的,一直滑虽然分页,但dom会越堆越多。还有可能是定时器和监听器没关闭)问了下领导知道有"虚拟滚动/虚拟列表"这么个东西,网上找了几个成熟的库。
vue2:
- tangbc/vue-virtual-scroll-list
- Taro virtualscroll (组件库里的组件)
- Akryum / vue-virtual-scroller
vue3:
- reactjser / vue3-virtual-scroll-list (Forked from vue2 vue-virtual-scroll-list )
- tnfe / vue3-infinite-list
- Akryum / vue-virtual-scroller
项目结构
v-for(item, index) 渲染的dom,循环在父组件,子组件很多逻辑过度依赖循环的item,index,并且子组件Item高度完全不可控。自己造轮子失败,无法确定准确高度,想不通rem怎么动态设置。不知道该如何抽离子组件, Item多页面复用。
搜遍全网,这几个基本不适合我这个情况: vue3-virtual-scroll-list 子组件以函数形式传入,无法监听prop和emit事件,官方issue有人提过这个问题,作者建议通过eventBus等其他方式交互,Taro virtualscroll 支持index,并且支持插槽,可以正常写子组件,事件交互都不受影响,但是它的动态高度是写死的 比如官方的例子: getItemSize 是一个有如下语法的函数 : (i: number): number, 通过这个函数可以动态设置元素宽高.
const getItemSize = (i: number): number => { switch (i % 4) { case 1: return 80; case 2: return 50; case 3: return 100; default: return 200; } };
官方也在git上给予我答复
只能放弃,最后用 Akryum / vue-virtual-scroller 的库基本实现需求。
Akryum / vue-virtual-scroller 的坑
如果是ios端H5,在这个库上滑/下滑滚动的时候,屏幕会闪动,并且严重的时候会中断滑动。Android/pc正常,很丝滑。
ios端h5解决方案/避雷:
- 浏览issue发现,降低版本可解决问题。我降到了2.0.0-beta.3
- 高度一定写死。不能用transform或者动画改变高度的值。不然闪动非常严重
- 开启硬件加速 -webkit-overflow-scrolling: touch; ios高版本自带
使用方法:
- 安装组件库 (上述问题降低版本至beta4以下)
npm install --save vue-virtual-scroller@next
- 全局引入/按需引入
//Install all the components: import VueVirtualScroller from 'vue-virtual-scroller' app.use(VueVirtualScroller) //Use specific components: import { RecycleScroller } from 'vue-virtual-scroller' app.component('RecycleScroller', RecycleScroller)
- 引入组件并设置固定高度
{{ item.message }}
.scroller { height: calc(100vh - 160px); -webkit-overflow-scrolling: touch; }
- 实现上拉加载 + loading图标(vant)
通过给虚拟滚动设置固定id,添加scroll监听
... let virtualScroller = document.getElementById('virtualScroller') virtualScroller ? virtualScroller.addEventListener('scroll', handleScroller) : ''
监听事件中判断是否触底 因为是移动端 用 scrollTop + clientHeight + 1 >= scrollHeight判断
const handleScroller = (e) => { if (scrollTop + clientHeight + 1 >= scrollHeight) { // virtualScrollerAllow.value = true // 触底逻辑 } }
坑
ios触底会回弹,导致疯狂触发触底的逻辑,建议用一个单独变量控制是否到底,再watch监听这个变量,true/false 来判断是否执行触底逻辑 (可能影响性能)
加入 “加载中/加载失败/到底文案及图标”,vant中list组件 虚拟滚动完算是废了😂 页面没有滚动,根本达不到vant触发逻辑,并且ios橡皮筋回弹会导致list鬼畜式触发。 如果h5依赖原生客户端,可以客户端方关闭并和h5通信,单h5页面网上方法好像并不能完全关闭橡皮筋效果。
通过插槽手动写个触底状态。 插槽有两个 before和after 在顶部和底部。 触底定义变量,通过监听变量的值请求接口,再请求接口回来根据改变变量的值
// 加载中... 加载失败,点击重新加载 到底了~
5.借助vant PullRefresh 实现下拉刷新
vant PullRefresh 中有disabled的选项,可以禁止下拉刷新,如果直接用PullRefresh包裹虚拟滚动,会导致无法向下滑动,任何位置下拉都会触发刷新逻辑。先用disabled禁用下拉刷新,通过监听虚拟滚动scroll中scrollTop,如果小于10或者等于0 (ios回弹还是体验不好) 将 disabled变为false
一直监听scroll也在影响性能
- 实现分页加载
只需在触底逻辑时,执行分页加载,并且新数据回来时,往原数组添加
/*const getIndexContent = async (isFirst) => { loadingStatus.value = 'loading' try { let topRes, baseRes if(isFirst) { topRes = await getIndexTop() indexTops.value.push(...topRes) } baseRes = await getIndexList() indexBases.value.push(...baseRes) if (indexTops.value.length === 0 && indexBases.value.length === 0) { loadingStatus.value = 'finished' } else { */ indexList.value = [ ...indexTops.value, ...indexBases.value ] /* virtualScrollerAllow.value = false // 活动上报 reportAdd(indexList.value.reduce((pre,cur)=>{ pre.push(cur.id) return pre; },[])) } } catch (e) { console.log('获取首页内容有误', e) loadingStatus.value = 'error' } } */
猜你喜欢
网友评论
- 搜索
- 最新文章
- 热门文章