最近在做一个
微信小程序
的直播模块
,模块里的聊天室功能是用scroll-view + 一维数组
的形式展示的,而且也没有进行任何的优化,导致用户的体验感比较差
首先模拟一下优化前的聊天室
情况
肉眼可见的蛋疼~
但是优化还是得优化滴,不优化是不可能滴,但是在开始之前,我觉得有必要把优化步骤拆分为以下两点?
1. 不再使用
scroll-into-view
设置锚点由于旧版本使用的是
scroll-view + 一维数组
的形式实现的,这就导致在数据添加后页面总会显示加载后的最后一条信息
,而不是加载前的最后一条信息
,因此上一任开发者使用了scroll-into-view
属性作为数据加载后的回位锚点
,但是由于锚点指向
的切换和数据加载
并不是同步发生的,这就导致出现回弹
的现象
2. 大量数据的处理
因为是
聊天室
功能,因此不可避免的需要加载大量的用户对话、图片等内容,又因为scroll-view
本身并不适合加载大量的数据(太菜了想不出来其他办法),故而需要在数据的加载和显示部分下点功夫处理一下
3. 附加功能处理
聊天室原本还有
返回底部
等功能存在,因此在完成优化后原本的功能也不能忽略
OK开工~
1、倒置scroll-view
为什么要倒置scroll-view
呢?从上面的第一点我们可以看出,如果需要正序地插入数据,那么就会不可避免地出现数据加载后无法显示后面数据
的情况,但是想要解决这种情况又需要使用scroll-into-view
属性,那么如果需要彻底地解决这个问题,就需要从问题的根源scroll-view
下手
首先是修改前
的代码?
<view class="live-content">这是一个直播画面</view> <scroll-view class="scroll" :scroll-y="true" :scroll-into-view="scrollIntoView" @scrolltoupper="upper" > <view :id="item.index" :style="{ backgroundColor: item.color, height: '200rpx', lineHeight: '200rpx', textAlign: 'center', }" v-for="item in scrollData" :key="item.index" > {{ item.data }} </view> </scroll-view>
const scrollIntoView = ref("index1"); const upper = () => { let lastNum = scrollData.value[0].data; let newArr = []; for (let index = 1; index <= 10; index++) { newArr.push({ color: getRandomColor(), data: lastNum + index, index: `index${lastNum + index}`, }); } scrollData.value.unshift(...newArr.reverse()); // 这里可以使用nextTick来替换一下,结果也是一样的,但是为了更明显的回弹效果我使用了定时器 setTimeout(() => { scrollIntoView.value = `index${lastNum}`; console.log("scrollIntoView :>>", scrollIntoView.value); }, 100); }; const getRandomColor = () => { return "#" + Math.random().toString(16).substr(2, 6); };
那么就先来试一下倒置scroll-view
到底也没有效果
首先我们需要给scroll-view
套上一个transform:rotate(180deg)
的属性,然后再给内部的子元素也套上同样的属性,别忘了给存放数据的数组
也倒置一下,最重要的,把scroll-view
上的scroll-into-view
属性去掉,就会得到这样的效果?
还有就是此时滚动条
的位置是在左边的,如果有需要可以使用CSS
属性去掉,或者自行模拟,下面是去去除滚动条的CSS样式
?
::-webkit-scrollbar { display:none; width:0; height:0; color:transparent; }
到这里还只是第一步
,下一步是如何下拉加载数据
。
此时我们的scroll-view
是处于倒置
的状态,也就是说顶部是底,底部才是顶
(搁着绕口令呢),所以之前使用的scrolltoupper触顶方法
要替换成scrolltolower触底方法
才能实现“下拉加载”
下面是目前的聊天室
看起来好多了
2、大量数据的处理
处理完回弹问题
后,就需要考虑如何处理大量数据
。由于uni-app
官方也在文档中提到scroll-view
加载大批量数据的时候性能较差,但无奈手头上也没有别的办法,只能死马当活马医了
我第一个想法就是非常经典的虚拟列表
,但是此前所看的很多关于虚拟列表的文章都是在web端
实现的,似乎小程序领域里并不是一个被经常采用的方法,但是所幸还是找到了如何在微信小程序实现虚拟列表
的资料,详情可以查看这篇文章?微信小程序虚拟列表
OK说干就干,那么第一步就是要明确实现虚拟列表需要什么样的数据结构
,虚拟列表其实简单地说就是当某一个模块的数据超出了可视范围就将其隐藏
,那么如何将数据分为多个模块呢?答案就是二维数组
首先将当前的页码
存储起来(默认为0),当触发下拉加载动作时页码+1
,然后以当前页码作为下标
存入数组
const currentShowPage=ref(0) const upper = () => { let len = scrollData.value[currentShowPage.value].length - 1; let lastNum = scrollData.value[currentShowPage.value][len].data; let newArr = []; currentShowPage.value += 1; for (let index = 1; index <= 10; index++) { newArr.push({ color: getRandomColor(), data: lastNum + index, index: `index${lastNum + index}`, }); } scrollData.value[currentShowPage.value] = newArr; };
当然别忘了在页面中也需要以二维数组
的形式循环数据
<scroll-view style="transform:rotate(180deg)" :scroll-y="true" @scrolltolower="upper"> <view v-for="(data, index) in scrollData" :key="index"> <view style="transform:rotate(180deg)" :style="{ backgroundColor: item.color, height: '200rpx', lineHeight: '200rpx', textAlign: 'center', }" v-for="item in data" :key="item.index" > {{ item.data }} </view> </view> </scroll-view>
数据结构
的问题解决了,那么接下来就是如何判断数据模块是否超出可视范围
。
首先我们需要知道每个数据模块的高度
,其实很简单,只需要为每个模块定义一个id
,然后在数据展示之后根据id
获取到该模块的节点信息
然后按顺序存储到数组中
即可
const pagesHeight = [] onReady(()=>{ setPageHeight() }) const upper = () => { ... nextTick(() => { // 每次获取新数据都调用一下 setPageHeight(); }); }; const setPageHeight = () => { let query = uni.createSelectorQuery(); query .select(`#item-${currentShowPage.value}`) .boundingClientRect(res => { pagesHeight[currentShowPage.value] = res && res.height; }) .exec(); };
OK,现在我们已经知道每个模块的高度
了,然后就是监听模块与可视窗口的交叉范围
。这里有两种方法,一种是JS获取可视窗口的高度与模块scrollTop进行差值计算
,另一种是使用小程序的createIntersectionObserver方法让程序自行监听交叉区域
这里我展示的是第二种方法,如果对第一种方法感兴趣的朋友可以向上看第二章开头我推荐的《微信小程序虚拟列表》文章
关于createIntersectionObserver方法
的使用其实很简单,我们只需要把可视窗口的id
以及需要监听的模块id
传入即可,详情看官方文档
onReady(() => { ... observer(currentShowPage.value); }); const upper = () => { ... nextTick(() => { // 每次获取新数据都调用一下 observer(); }); }; // 允许渲染的数组下标,需要设置默认值 const visiblePagesList = ref([-1,0,1]) const observer = pageNum => { const observeView = wx .createIntersectionObserver() .relativeTo("#scroll", { top: 0, bottom: 0 }); observeView.observe(`#item-${pageNum}`, res => { if (res.intersectionRatio > 0) visiblePagesList.value = [pageNum - 1, pageNum, pageNum + 1]; }); };
最后就是在页面中判断该模块是否允许被渲染(也就是是否存储在visiblePagesList数组中)
,这里就很简单了,只需要写一个方法在页面中调用即可
<scroll-view id="scroll" class="scroll" :scroll-y="true" @scrolltolower="upper"> <view v-for="(data, index) in scrollData" :key="index" :id="'item-' + index"> <template v-if="includePage(index)"> <view class="scroll-item" :style="{ ... }" v-for="item in data" :key="item.index" > {{ item.data }} </view> </template> <view v-else :style="{ height: pagesHeight[index] }"></view> </view> </scroll-view>
const includePage = index => { return visiblePagesList.value.indexOf(index) > -1; };
来看看效果如何
额...似乎没有太大区别,那我们看看页面结构到底也没有将可视区域外的内容切换为空白view
成功!
3、功能调整
聊天室原本还有回底功能
等,也不能忘了加上
这个部分就比较简单了,只需要直接使用scroll-view
的scroll-top属性
,然后通过在scroll回调中动态记载scroll-top的值即可
下面是部分代码
<scroll-view id="scroll" class="scroll" :scroll-y="true" :scroll-top="currentTop" @scroll="handle_scroll" @scrolltolower="upper" > ... </scroll-view> <view v-show="showGoBottom" class="go-back-btn" @click="handle_goBottom">回底</view>
let scrollTop; const currentTop = ref(0); const showGoBottom = ref(false); const handle_scroll = throttle(event => { scrollTop = event[0].detail.scrollTop; if (scrollTop > 300) { showGoBottom.value = true; } }, 100); const handle_goBottom = () => { currentTop.value = scrollTop; nextTick(() => { currentTop.value = 0; }); showGoBottom.value = false; };
大功告成~
最后附上demo仓库
https://gitee.com/huang-qihao123/virtual-list-demo
推荐:《uniapp教程》
以上是聊聊uniapp的scroll-view下拉加载的详细内容。更多信息请关注PHP中文网其他相关文章!

本文讨论了有关移动和网络平台的调试策略,突出显示了Android Studio,Xcode和Chrome DevTools等工具,以及在OS和性能优化的一致结果的技术。

文章讨论了用于Uniapp开发的调试工具和最佳实践,重点关注Hbuilderx,微信开发人员工具和Chrome DevTools等工具。

本文讨论了跨多个平台的Uniapp应用程序的端到端测试。它涵盖定义测试方案,选择诸如Appium和Cypress之类的工具,设置环境,写作和运行测试,分析结果以及集成

本文讨论了针对Uniapp应用程序的各种测试类型,包括单元,集成,功能,UI/UX,性能,跨平台和安全测试。它还涵盖了确保跨平台兼容性,并推荐Jes等工具

本文讨论了UNIAPP开发中的共同绩效抗模式,例如过度的全球数据使用和效率低下的数据绑定,并提供策略来识别和减轻这些问题,以提高应用程序性能。

本文讨论了通过压缩,响应式设计,懒惰加载,缓存和使用WebP格式来优化Uniapp中的图像,以更好地进行Web性能。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

SublimeText3 Linux新版
SublimeText3 Linux最新版

WebStorm Mac版
好用的JavaScript开发工具

禅工作室 13.0.1
功能强大的PHP集成开发环境

Atom编辑器mac版下载
最流行的的开源编辑器