用BetterScroll打造丝滑滚动体验的实践与避坑指南
优化前:卡得不行
最近接手了一个移动端项目,里面用到了 Better Scroll 实现列表滚动。一开始觉得这玩意儿挺简单,结果上线后用户反馈说“页面卡得像PPT”。我试了一下,确实优化前的滚动体验差到爆炸,特别是在长列表和复杂 DOM 结构下,手指滑动时能明显感觉到延迟和掉帧。
更离谱的是,有些页面在低端机上直接崩了——不是白屏,而是 Better Scroll 根本不动,完全没法滚。当时我就意识到,这个问题不解决,这个功能基本等于废了。
找到瓶颈了!
问题摆在眼前,怎么解决呢?我先用了 Chrome DevTools 的 Performance 工具跑了一下,发现几个大问题:
- 重绘和回流太频繁:每次滚动触发了大量的 layout 和 paint 操作,特别是动态计算高度的时候。
- 事件监听过多:Better Scroll 默认绑定了 touchmove 等事件,但这些事件在复杂 DOM 下性能开销很大。
- 数据量太大:部分列表一次性渲染了几百条数据,直接把 DOM 节点撑爆了。
简单总结就是:DOM 太多、事件太重、计算太频繁。知道问题在哪就好办了,接下来就是一顿折腾。
优化方案一:虚拟列表拯救世界
优化的第一步,我决定引入虚拟列表(Virtual List)。这个概念其实很简单:只渲染当前视口内的内容,其他部分用占位符代替。这样一来,DOM 节点数量从几百个直接降到了十几个,效果立竿见影。
下面是优化前后的代码对比:
// 优化前:直接渲染所有数据
const list = document.querySelector('.scroll-list');
data.forEach(item => {
const li = document.createElement('li');
li.textContent = item.name;
list.appendChild(li);
});
// 优化后:使用虚拟列表
const visibleCount = 10; // 视口内最多显示10条
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;
const visibleData = data.slice(startIndex, endIndex);
visibleData.forEach((item, index) => {
const li = document.createElement('li');
li.style.position = 'absolute';
li.style.top = ${(startIndex + index) * itemHeight}px;
li.textContent = item.name;
list.appendChild(li);
});
优化后,页面滚动变得丝滑流畅,尤其是在低端机上,效果特别明显。不过这里有个踩坑点:虚拟列表的高度计算一定要精确,不然会出现滚动条错乱的问题。我试了好几次才发现,原来是因为某些样式没写对。
优化方案二:减少事件监听
Better Scroll 默认会绑定很多事件,比如 touchstart、touchmove 和 touchend。如果列表很长,这些事件会导致性能瓶颈。我的做法是手动调整配置,关闭一些不必要的事件监听。
具体代码如下:
import BScroll from '@better-scroll/core';
const bs = new BScroll('.wrapper', {
probeType: 3, // 监听滚动位置变化
click: false, // 关闭点击事件监听
momentum: true, // 启用惯性滚动
bounce: false, // 关闭边界回弹效果
});
这里有个小技巧:probeType 设置为 3,这样可以实时监听滚动位置,同时减少不必要的事件触发。另外,我把 click 设置为 false,因为这个项目不需要点击事件,关掉后性能提升很明显。
优化方案三:懒加载图片
还有一个问题是图片太多,导致页面加载时间过长。优化前,图片资源全部一次性加载,内存占用直接飙高。后来我改成了懒加载,只有当图片进入视口时才加载。
代码实现也很简单:
const images = document.querySelectorAll('.lazy-image');
function lazyLoad() {
images.forEach(img => {
if (img.getBoundingClientRect().top < window.innerHeight && !img.src) {
img.src = img.dataset.src;
}
});
}
window.addEventListener('scroll', lazyLoad);
lazyLoad(); // 初始化时也调用一次
优化后,首屏加载时间从 5 秒降到了 800 毫秒左右,效果非常明显。不过要注意:懒加载的阈值设置要合理,否则可能会出现图片加载滞后的问题。
优化后:流畅多了
经过这一系列优化,页面的滚动性能提升了一个档次。以下是具体的性能数据对比:
- 滚动帧率:从平均 20fps 提升到 55fps。
- 首屏加载时间:从 5 秒降到 800 毫秒。
- 内存占用:从 120MB 降到 40MB。
当然,也不是完全没有问题。比如虚拟列表在快速滚动时偶尔会出现轻微的闪烁,但整体来说影响不大。毕竟鱼和熊掌不可兼得嘛。
性能数据对比
最后再补充一下,整个优化过程让我深刻认识到性能优化的重要性。Better Scroll 虽然是个好工具,但如果用得不对,反而会成为性能杀手。通过虚拟列表、减少事件监听和懒加载图片这三个核心方案,我们成功解决了性能瓶颈。
以上是我个人对 Better Scroll 性能优化的完整讲解,有更优的实现方式欢迎评论区交流。这个技巧的拓展用法还有很多,后续会继续分享这类博客。希望这篇文章能帮到有同样需求的同学。

暂无评论