移动端页面滚动性能调优

最近在做一个可视化平台的移动端适配,遇到了在移动端页面滚动卡顿的情况,遂进行了一些优化,做一小记:

-webkit-overflow-scrolling: touch
-webkit-transform: translateZ(0px)

上网搜索移动端滑动卡顿,出现次数最多的解决方案便是这两个。他们的原理其实差不多,遇到上述属性时浏览器会创建一个新的layer,layer中的各种操作会使用一个新的线程去处理,所以某些情况下确实可以提高滚动性能。
当然也不是layer越多越好,因为每次生成一个新的layer,需要额外进行一次composite的操作,也需要耗费时间。
不过这两个方案对我都没什么用处。

iscroll

既然原生滚动折腾半天没有什么起色,那么想到用iscroll来做页面模拟滚动,可能会好点。用了以后确实有所提高,不过ios依然略卡,adr相当卡。并且引申出了其他两个问题:

  1. 处于性能考虑,iscroll默认在touchStart的时候,将event preventDefault了,导致touch之后的click事件将不再触发
  2. overflow:scorll的组件不再触发scroll

为解决这个问题我也大费周章,通过全局变量控制了下特定情况下才进行preventDefault。然而问题还是没有彻底解决。

performance分析

让我们来看看引起页面卡顿的罪魁祸首:

没错,就是这个react-draggable库中的getControlPosition方法。让我们来看看这个方法都干了什么:

1
2
3
4
5
6
7
8
9
10
function getControlPosition(e /*: MouseTouchEvent*/, touchIdentifier /*: ?number*/, draggableCore /*: DraggableCore*/) /*: ?ControlPosition*/ {
var touchObj = typeof touchIdentifier === 'number' ? (0, _domFns.getTouch)(e, touchIdentifier) : null;
if (typeof touchIdentifier === 'number' && !touchObj) return null; // not the right touch
var node = _reactDom2.default.findDOMNode(draggableCore);
// User can provide an offsetParent if desired.

var offsetParent = draggableCore.props.offsetParent || node.offsetParent || node.ownerDocument.body;

return (0, _domFns.offsetXYFromParent)(touchObj || e, offsetParent);
}

注意第7行,他尝试去获取一个node的offsetParent, 这个操作会直接引起浏览器的reflow。所以大量的reflow操作变引起了页面的卡顿。找到了源头我们处理一下相关代码问题就解决了。

 
 
 
原文地址:https://www.cnblogs.com/guochongbin/p/10612858.html