최근
WeChat 미니 프로그램
의라이브 방송 모듈
을 작업 중입니다. 모듈의 채팅방 기능은scroll-view + one-를 사용합니다. 차원 배열
코드> 형태로 표시되며, 최적화가 이루어지지 않아 사용자 경험이 좋지 않습니다微信小程序
的直播模块
,模块里的聊天室功能是用scroll-view + 一维数组
的形式展示的,而且也没有进行任何的优化,导致用户的体验感比较差
首先模拟一下优化前的聊天室
情况
肉眼可见的蛋疼~
但是优化还是得优化滴,不优化是不可能滴,但是在开始之前,我觉得有必要把优化步骤拆分为以下两点?
1. 不再使用
scroll-into-view
设置锚点由于旧版本使用的是
scroll-view + 一维数组
的形式实现的,这就导致在数据添加后页面总会显示加载后的最后一条信息
,而不是加载前的最后一条信息
,因此上一任开发者使用了scroll-into-view
属性作为数据加载后的回位锚点
,但是由于锚点指向
的切换和数据加载
并不是同步发生的,这就导致出现回弹
的现象
2. 大量数据的处理
因为是
聊天室
功能,因此不可避免的需要加载大量的用户对话、图片等内容,又因为scroll-view
本身并不适合加载大量的数据(太菜了想不出来其他办法),故而需要在数据的加载和显示部分下点功夫处理一下
3. 附加功能处理
聊天室原本还有
返回底部
等功能存在,因此在完成优化后原本的功能也不能忽略
OK开工~
为什么要倒置scroll-view
呢?从上面的第一点我们可以看出,如果需要正序地插入数据,那么就会不可避免地出现数据加载后无法显示后面数据
的情况,但是想要解决这种情况又需要使用scroll-into-view
属性,那么如果需要彻底地解决这个问题,就需要从问题的根源scroll-view
下手
首先是修改前
的代码?
<view>这是一个直播画面</view> <scroll-view> <view> {{ item.data }} </view> </scroll-view>
const scrollIntoView = ref("index1"); const upper = () => { let lastNum = scrollData.value[0].data; let newArr = []; for (let index = 1; index { 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触底方法
才能实现“下拉加载”
下面是目前的聊天室
채팅방
상황을 시뮬레이션 하기 전 최적화🎜 눈에 보이는 계란통~🎜 🎜그래도 최적화는 해야죠. 하지만 시작하기 전에 최적화 단계를 다음 두 가지로 나누어야 할 것 같은데요?🎜🎜🎜1. 스크롤 뷰
앵커 포인트 설정을 사용🎜🎜이전 버전은 스크롤 뷰 + 1차원 배열
형식으로 구현되었기 때문에 이러한 결과가 나타납니다. 데이터 추가 후 페이지가 항상 가득 차 있는 경우 로딩 전 마지막 메시지
대신 로딩 후 마지막 메시지
가 표시되므로 이전 개발자는 스크롤을 사용했습니다. -into-view
>이 속성은 데이터가 로드된 후 앵커 포인트
의 역할을 합니다. 그러나 앵커 포인트
와 가 전환되었기 때문입니다. >데이터 로딩
이 동시에 일어나지 않아 바운스
현상🎜🎜🎜대량의 데이터를 처리🎜🎜하기 때문입니다. 채팅방
기능이므로 대량의 사용자 대화나 사진, 기타 컨텐츠를 로딩하는 것은 불가피하며, 스크롤뷰
자체가 로딩에 적합하지 않기 때문입니다. 데이터의 양이 많아(다른 방법을 생각하기에는 아까움) 데이터에 로드해야 합니다. 로드 및 표시 부분 작업🎜🎜🎜추가 기능 처리 Strong>🎜🎜채팅방에는 원래 맨아래로 돌아가기
등의 기능이 있어서 최적화가 완료된 후에는 원래 기능을 무시할 수 없습니다🎜🎜시작해도 좋아요~🎜스크롤- 보기
를 반전하는 이유는 무엇인가요? 위의 첫 번째 점에서 알 수 있듯이, 데이터를 양의 순서로 삽입해야 한다면 필연적으로 데이터가 로드된 후 후속 데이터를 표시할 수 없는
상황이 발생하지만, 우리는 이 상황을 해결하려면 scroll-into-view
속성을 사용해야 하므로 이 문제를 완전히 해결하려면 문제의 근원인 scroll-view부터 시작해야 합니다.
🎜🎜우선 수정 전 코드
?🎜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 <pre class="brush:php;toolbar:false"><scroll-view> <view> <view> {{ item.data }} </view> </view> </scroll-view>
스크롤 뷰 반전
을 시도해 보지만 효과가 없습니다🎜🎜먼저 해야 할 일은 scroll-view
이전 transform:rotate(180deg)
의 속성을 설정한 다음 동일한 속성을 내부 하위 요소에 적용하는 것을 잊지 마세요. 데이터를 저장하는 배열
도 마찬가지입니다. 가장 중요한 것은 scroll-view
에서 scroll-into-view
속성을 제거하는 것입니다. 이런 효과가 나올까요?🎜🎜🎜🎜스크롤바의 위치는 왼쪽에 있습니다. 필요한 경우 <code>CSS
속성을 사용하여 제거하거나 직접 시뮬레이션할 수 있습니다. 스크롤 막대를 제거하는 CSS 스타일
은 다음과 같습니다.🎜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(); };
첫 번째 단계
일 뿐입니다. 다음 단계는 데이터를 풀다운하고 로드하는 방법. 🎜🎜현재 <code>스크롤뷰
는 반전된
상태입니다. 즉, 상단이 하단이고 하단이 상단
입니다. > (텅 트위스터는 따로 남겨두세요), "풀다운 로딩"🎜🎜🎜🎜다음은 현재 채팅방훨씬 좋아보이네요🎜🎜🎜🎜回弹问题
后,就需要考虑如何处理大量数据
。由于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 <p>当然别忘了在页面中也需要以<code>二维数组</code>的形式循环数据</p><pre class="brush:php;toolbar:false"><scroll-view> <view> <view> {{ 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> <view> <template> <view> {{ item.data }} </view> </template> <view></view> </view> </scroll-view>
const includePage = index => { return visiblePagesList.value.indexOf(index) > -1; };
来看看效果如何
额...似乎没有太大区别,那我们看看页面结构到底也没有将可视区域外的内容切换为空白view
成功!
聊天室原本还有回底功能
等,也不能忘了加上
这个部分就比较简单了,只需要直接使用scroll-view
的scroll-top属性
,然后通过在scroll回调中动态记载scroll-top的值即可
下面是部分代码
<scroll-view> ... </scroll-view> <view>回底</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의 스크롤뷰 드롭다운 로딩에 대해 이야기해보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!