##首先模擬一下優化前的最近在做一個
微信小程式
的直播模組
,模組裡的聊天室功能是用scroll -view 一維數組
的形式展示的,而且也沒有進行任何的優化,導致用戶的體驗感比較差
聊天室情況
1.不再使用scroll-into-view
由於舊版使用的是設定錨點
scroll-view 一維數組
的形式實現的,這就導致在資料新增後頁面總是會顯示
載入後的最後一個資訊,而不是
載入前的最後一則資訊,因此上一任開發者使用了
scroll-into-view屬性作為資料載入後的
回位錨點,但是由於
錨點指向的切換和
資料載入並不是同步發生的,這就導致出現
回彈的現象
2. 大量資料的處理
因為是聊天室
功能,因此不可避免的需要載入大量的使用者對話、圖片等內容,又因為
scroll-view本身並不適合載入大量的資料(太菜了想不出來其他辦法),故而需要在資料的載入和顯示部分下點功夫處理一下
OK開工~1、倒置scroll-view為什麼要倒置#3. 附加功能處理
聊天室原本還有返回底部
等功能存在,因此在完成優化後原本的功能也不能忽略
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觸底方法才能實現“下拉加載”
下面是目前的
聊天室看起來好多了
回弹问题
后,就需要考虑如何处理大量数据
。由于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的scroll-view下拉加載的詳細內容。更多資訊請關注PHP中文網其他相關文章!