滚动条滚动和鼠标/触摸板滚动之间的区别是DOM元素位置缓慢

时间:2014-11-20 14:12:51

标签: javascript performance safari scroll webkit

我对Safari有一点问题 - 当我想更新DOM元素在滚动事件上的位置时,Safari似乎没有赶上更改(导致跳跃延迟效果)。 我在其他浏览器(Chrome,FF,IE8 +)上查看过,这似乎是Safari特有的。

enter image description here

我做了一个jsfiddle来说明我的问题:

$("#container").on("scroll", function() {
    $("#slide").css({
        left: $("#container").scrollLeft() + "px"
    });

    var leftPos = 0;
    for(var i = 0; i < 2000 ; i++) {
        leftPos = $("#slide").css("left");
    }  
    $("#info").text(leftPos); 
});

http://jsfiddle.net/a4b86et3/2/

正如您所看到的,我在每个滚动条上添加了一个额外的DOM读取循环,以模拟每个事件发生时“正在进行的更多操作”,因为此机制是更大项目的一部分,其中包含许多其他DOM操作。 (注意,除了Safari之外,这个例子在任何地方都很顺利)

另外,我使用jQuery只是为了方便,实际项目使用纯js。

我设法部分解决了问题

left = x属性更改为transform = translate3d(x,0,0),以便浏览器使用GPU。

$("#container").on("scroll", function() {
    $("#slide").css({
        '-webkit-transform': 'translate3d(' + $("#container").scrollLeft() + 'px, 0, 0)'
    });

    var leftPos = 0;
    for(var i = 0; i < 1900 ; i++) {
        leftPos = $("#slide").css("left");
    }  
    $("#info").text(leftPos);

});

http://jsfiddle.net/a4b86et3/3/

然而,有时我在滚动时仍然会遇到轻微的延迟/故障。

但是,更重要的是,当我使用鼠标滚动或触摸板时,此修复不会影响滚动!虽然拖动滚动条的方式更好,但使用上述任何一种方法都会让我回到最初的问题。

为什么会发生这种情况以及如何解决这个问题?


TL;博士; - 在滚动时更改元素位置时Safari很慢;使用鼠标滚动/触摸板时,translate3d似乎无法正常工作。

1 个答案:

答案 0 :(得分:0)

我有完全相同的问题,我花了一些时间来弄清楚这个问题。这是一个更新的jsfiddle,向您展示如何在Safari中解决问题:http://jsfiddle.net/a4b86et3/4/

function handle_scroll() {
  $("#slide").css({
    '-webkit-transform': 'translate3d(' + $("#container").scrollLeft() + 'px, 0, 0)'
  });

  var leftPos = 0;
  for(var i = 0; i < 1900 ; i++) {
    leftPos = $("#slide").css("left");
  }  
  $("#info").text(leftPos);
}

$("#container").on("scroll", handle_scroll);
$("#container").on('mousewheel', function(e) {
  e.preventDefault()

  var maxX = this.scrollWidth  - this.offsetWidth
  var maxY = this.scrollHeight - this.offsetHeight
  this.scrollTop  = Math.max(0, Math.min(maxY, this.scrollTop  - e.originalEvent.wheelDeltaY))
  this.scrollLeft = Math.max(0, Math.min(maxX, this.scrollLeft + e.originalEvent.wheelDeltaX))

  handle_scroll(e)
})

简而言之:如果您自己处理鼠标滚轮事件,请在那里计算正确的滚动值,然后调用处理程序代码,事情就开始工作了。

我不确定为什么Safari会让你跳过这个箍,但幸运的是这个修复工作并不太复杂。

希望这有帮助。