uni-app 在安卓上长列表非常卡顿应该怎么优化?
2023年09月25日 459
长列表渲染性能问题一直是手机端的难题,本文介绍几种解决方法。
问题描述
在使用 uni-app 开发小程序或者是 APP 时,实现滚动到底部自动加载下一页,当列表项很多有几百条时,会出现卡顿的情况,特别时在安卓手机时,这个问题会更严重。
出现这个问题的原因其实也很明显,就是因为列表中经常有图片和文字,如果渲染过多就会占用很大的内存,这时候的滚动操作非常耗资源,导致手机卡顿。
解决方法
在小程序端
小程序端需要用到 uni-scroll-view 这个官方组件,原理是监听滚动事件,计算出现在可视区域内的列表,只渲染这部分列表,这样就能大大减少资源损耗。核心实现代码如下:
<template>
<uni-scroll-view :style="{height: height + 'px'}" @scroll="onScroll">
<ul>
<li v-for="(item, index) in visibleData" :key="index">{{ item }}</li>
</ul>
</uni-scroll-view>
</template>
<script>
export default {
data() {
return {
// 总数据
data: [],
// 可视区域高度
height: 0,
// 可视区域顶部数据序号
startIndex: 0,
// 可视区域底部数据序号
endIndex: 0,
// 可视区域数据
visibleData: []
};
},
mounted() {
// 初始化数据
this.initData();
// 监听可视区域高度变化
uni.getSystemInfo({
success: (res) => {
this.height = res.windowHeight;
}
});
},
methods: {
initData() {
// 这里为了演示,生成大量数据
for (let i = 0; i < 10000; i++) {
this.data.push(`数据 ${i+1}`);
}
// 初始化可视区域数据
this.visibleData = this.data.slice(0, 30);
this.endIndex = 29;
},
onScroll(e) {
// 滚动事件
const scrollTop = e.detail.scrollTop;
const itemHeight = 50; // 每个数据项高度
const visibleCount = Math.ceil(this.height / itemHeight); // 可见数据项个数
const startIndex = Math.floor(scrollTop / itemHeight); // 开始渲染的数据序号
if (startIndex !== this.startIndex) {
this.startIndex = startIndex;
this.endIndex = this.startIndex + visibleCount - 1;
this.visibleData = this.data.slice(this.startIndex, this.endIndex + 1);
}
}
}
}
</script>
上面的这段代码可以运行在小程序端,其实运行的 APP 端也没问题,但在 APP 端我们有更好的解决方式。
在 APP 端
在开发 app 端时,uni-app 官方为了解决长列表的问题,专门写了 list 这个组件,这是一个 nvue 专用组件,在这个组件只能在 nvue 下使用,性能非常好,原理是 list 在不可见部分的渲染资源回收时,有特殊的优化处理。
<template>
<list>
<!-- 需要注意,因为回收机制问题,这里不能使用 index 作为 key 的唯一标识 -->
<cell v-for="(item, index) in dataList" :key="item.id">
<text>{{item.name}}</text>
</cell>
</list>
</template>
<script>
export default {
data () {
return {
dataList: [{id: "aaa", name: 'AAA'}, {id: "bbb", name: 'BBB'}, {id: "ccc", name: 'CCC'}]
}
}
}
</script>
跨端兼容方案
如果我们写的页面需要跨端,也就是一套代码想要同时运行在 APP 或者小程序,最好的解决方法是用官方的 uni-list 组件,代码也很简洁:
<uni-list>
<uni-list-item title="我是一个骚标题" ></uni-list-item>
<uni-list-item title="我是一个骚标题" ></uni-list-item>
<uni-list-item title="我是一个骚标题" ></uni-list-item>
</uni-list>
这是一个符合 easycom 规范组件,只需组件文件放到项目中,在页面 template
中可直接使用,不需要在页面中 import
和注册 components
。详细的用法可以查看 uni-list 官方的使用文档。