先说使用场景,一次加载很多数据造成小程序卡顿的问题 ,找了好多都没有好的解决办法,要么太过复杂,然后研究了两天通过简单的办法实现,先根据数量把高度撑开,然后根据滚动位置渲染指定的数据就可以了, 性能简直不要太好。先看效果(实际业务效果要好于测试效果)。
小程序列表性能
DataManage.js 封装
- function DataManage() {
-
- //**********************************************************数据
- let Data = {
- dataSource: [],//数据源
- heatData: [] //热数据(需要渲染的数据)
- }
-
- //**********************************************************配置
- let BaseConfig = { //基本配置信息(不需要覆盖的配置)
- triggerTime: 0, //滚动时间
- triggerTop: 0, //滚动top位置
- voidViewHeight: 0,//虚拟View高度
- pagingIndex: -1, //切换分页索引
- dataEnd: -1 //数据结束范围
- }
- let PagingConfig = { //分页配置(可改变)
- pageSize: 50, //分页大小
- cardHeight: 55, //卡片高度
- pagingBoundary: 20,//切换数据边界值(此值需要小于分页大小)
- topBoundary: 20, //数据上移边界
- callback: '',//回调方法
- debug: false //输出日志
- }
-
- let CallbackFn = null //回调方法
-
- //**********************************************************内部方法
- const refreshData = (viewData) => {//刷新数据
- Data.heatData = viewData.viewList
- CallbackFn(viewData)
- }
- const virtualPaging = () => {//虚拟分页
- if (Data.dataSource.length <= PagingConfig.pageSize) {//不分页处理
- refreshData({ viewList: Data.dataSource, voidViewHeight: BaseConfig.voidViewHeight, viewListTop: 0 })
- return;
- }
- let currentIndex = Math.floor(BaseConfig.triggerTop / PagingConfig.cardHeight)//根据位置计算当前索引值
- if (BaseConfig.pagingIndex == -1 || (currentIndex != BaseConfig.pagingIndex && Math.abs(currentIndex - BaseConfig.pagingIndex) >= PagingConfig.pagingBoundary)) {
- //数据范围
- let dataS = currentIndex - PagingConfig.topBoundary < 0 ? 0 : currentIndex - PagingConfig.topBoundary//起始位置
- let dataE = dataS + PagingConfig.pageSize//结束位置
- if (Math.abs(Data.dataSource.length - dataE) <= PagingConfig.pagingBoundary)//避免丢失最后的数据
- dataE = Data.dataSource.length
- if (dataE == BaseConfig.dataEnd)//避免总数据量只大于分页数造成的多一次渲染
- return;//返回后,此处会触发多次,因为下面的变量没有更新
- //刷新数据
- refreshData({
- viewList: Data.dataSource.slice(dataS, dataE),
- voidViewHeight: BaseConfig.voidViewHeight,
- viewListTop: dataS * PagingConfig.cardHeight
- })
- //保存此次分页位置
- BaseConfig.dataEnd = dataE
- BaseConfig.pagingIndex = currentIndex
- //打印日志
- if (PagingConfig.debug)
- console.log("虚拟分页,位置索引->", currentIndex, "上次分页索引->", BaseConfig.pagingIndex, "数据范围[" + dataS + "-" + dataE + "]")
- }
- }
-
- //**********************************************************对外方法
- /**
- * 初始化
- */
- const Init = (_pagingConfig, _data, _callback) => {
- PagingConfig = { ...PagingConfig, ..._pagingConfig }
- Data.dataSource = _data
- CallbackFn = _callback
- BaseConfig = {
- triggerTime: 0,
- triggerTop: 0,
- voidViewHeight: _data.length * PagingConfig.cardHeight,
- pagingIndex: -1,
- dataEnd: -1
- }
- virtualPaging()
- }
-
- /**
- * scroll-view 滚动事件
- */
- const RollEvent = (e) => {
- if (Data.dataSource.length <= PagingConfig.pageSize)
- return;
- BaseConfig.triggerTime = new Date().getTime()
- BaseConfig.triggerTop = e.detail.scrollTop
- virtualPaging()
- }
- return {
- Init, RollEvent
- }
- }
-
- export {
- DataManage as dm
- }
test1.js调用
-
- import { dm } from "../../utils/DataManage"
- const DM = dm()
- Page({
-
- /**
- * 页面的初始数据
- */
- data: {
- TestAllData: [],//为了测试位置 对齐
-
- voidViewHeight: 0,//虚拟列表高度
- viewListTop: 0, //数据列表Top起始位置
- viewList: [], //显示的数据
- },
-
- rollEvent(e) {//滚动事件
- DM.RollEvent(e)
- },
-
- /**
- * 生命周期函数--监听页面加载
- */
- onLoad(options) {
- let DataSource = []
- for (var i = 0; i < 10000; i++) {
- DataSource.push({ sn: i, text: "第" + i + "个订单" })
- }
- this.setData({ TestAllData: DataSource })
-
- DM.Init({ debug: true }, DataSource, (data) => { this.setData(data)})
- }
- })
test1.wxml 布局
-
- <view class="container">
- <view style="position: fixed; top: 0; background-color: blueviolet; width: 100%; height: 25px; z-index: 999; ">
- <navigator url="/pages/order/order">订单navigator>
- view>
- <view style="margin-top:25px ; ">
- <scroll-view enhanced scroll-y bindscroll="rollEvent" style="height: calc(100vh - 25px);">
-
- <view class="voidView" style="height:{{voidViewHeight}}px;">
- <view style=" height: 55px; align-content: center; color: greenyellow;" wx:for="{{TestAllData}}" wx:key="sn">
- {{item.sn }}view>
- view>
-
- <view class="dataView" style="top:{{viewListTop<0?0:viewListTop}}px">
- <view class="orderCard" wx:for="{{viewList}}" wx:key="sn">
- {{item.sn }} - {{item.text}}
- view>
- view>
-
- scroll-view>
- view>
- view>
test1.wxss 样式
- ::-webkit-scrollbar {
- width: 0;
- height: 0;
- color: transparent;
- }
-
- /* 占位元素 */
- .voidView {
- position: absolute;
- width: 30px;
- background-image: url('http://192.168.1.8:808/images/back.png');
- }
-
- /* 列表容器 */
- .dataView {
- width: 100vw;
- padding-left: 30px;
- position: absolute;
- }
-
- /* 订单卡片 */
- .orderCard {
- height: 50px;
- background-color: coral;
- margin: 5px 5px 5px 5px;
- text-align: center;
- font-size: 24px;
- }