最近在做一个可视化平台的移动端适配,遇到了在移动端页面滚动卡顿的情况,遂进行了一些优化,做一小记:
-webkit-overflow-scrolling: touch
-webkit-transform: translateZ(0px)
上网搜索移动端滑动卡顿,出现次数最多的解决方案便是这两个。他们的原理其实差不多,遇到上述属性时浏览器会创建一个新的layer,layer中的各种操作会使用一个新的线程去处理,所以某些情况下确实可以提高滚动性能。
当然也不是layer越多越好,因为每次生成一个新的layer,需要额外进行一次composite的操作,也需要耗费时间。
不过这两个方案对我都没什么用处。
iscroll
既然原生滚动折腾半天没有什么起色,那么想到用iscroll来做页面模拟滚动,可能会好点。用了以后确实有所提高,不过ios依然略卡,adr相当卡。并且引申出了其他两个问题:
- 处于性能考虑,iscroll默认在touchStart的时候,将event preventDefault了,导致touch之后的click事件将不再触发
- overflow:scorll的组件不再触发scroll
为解决这个问题我也大费周章,通过全局变量控制了下特定情况下才进行preventDefault。然而问题还是没有彻底解决。
performance分析
让我们来看看引起页面卡顿的罪魁祸首:
没错,就是这个react-draggable库中的getControlPosition方法。让我们来看看这个方法都干了什么:
1
|
function getControlPosition(e /*: MouseTouchEvent*/, touchIdentifier /*: ?number*/, draggableCore /*: DraggableCore*/) /*: ?ControlPosition*/ {
|
注意第7行,他尝试去获取一个node的offsetParent, 这个操作会直接引起浏览器的reflow。所以大量的reflow操作变引起了页面的卡顿。找到了源头我们处理一下相关代码问题就解决了。