移动端列表滚动卡顿,优化后还是不流畅怎么办?

爱学习的春凤 阅读 43

开发移动端列表页面时,当列表项超过50条左右,滚动就明显卡顿。尝试用display: none隐藏视口外元素,并改用position: absolute定位列表项,但滚动仍然有掉帧现象,特别是快速滑动时。

代码结构类似这样:


<div class="scroll-container">
  <div class="list-item" v-for="item in items" :style="{ top: calcTop(item) }">
    
  </div>
</div>

已经做了防抖重排、减少DOM操作,甚至尝试开启will-change: transform,但效果有限。是不是还有其他隐藏性能瓶颈没考虑到?

我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
金梅 Dev
你这个情况,50条列表就卡顿,很明显是渲染压力太大了。光靠 display: noneposition: absolute 是不够的,得用更高效的方案:虚拟列表。

简单说下思路:只渲染视口内可见的几条数据,其他的先不渲染。当用户滚动时,动态计算哪些数据需要显示,更新 DOM。这样任何时候 DOM 树都很小,效率更高。

给你个简单的实现例子:

class VirtualList {
constructor(container, items, itemHeight) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;

this.render();
this.bindScroll();
}

render() {
const visibleCount = Math.ceil(this.container.clientHeight / this.itemHeight) + 2;
this.visibleItems = Array(visibleCount).fill(null).map(() => document.createElement('div'));
this.visibleItems.forEach(item => this.container.appendChild(item));
}

bindScroll() {
let lastTime = 0;
this.container.addEventListener('scroll', () => {
const now = Date.now();
if (now - lastTime < 16) return; // 避免高频触发
lastTime = now;

const start = Math.floor(this.container.scrollTop / this.itemHeight);
this.updateVisibleItems(start);
});
}

updateVisibleItems(startIndex) {
this.visibleItems.forEach((item, i) => {
const index = startIndex + i;
if (index < this.items.length) {
item.textContent = this.items[index];
item.style.top = index * this.itemHeight + 'px';
item.style.position = 'absolute';
}
});
}
}

// 使用示例
const container = document.querySelector('.scroll-container');
new VirtualList(container, Array.from({ length: 1000 }, (_, i) => Item ${i}), 50);


注意:
1. 这里假设每个列表项高度固定,如果高度不固定会复杂一些。
2. 滚动事件加了简单防抖,避免掉帧。
3. 如果用框架(比如 Vue/React),可以用类似逻辑封装成组件。

试试这个方案,性能应该能提升不少。要是还卡,可能得看设备性能或者其他地方有没有问题了。
点赞 12
2026-01-29 09:01