【问题标题】:Move html elements positions slow on iOS在 iOS 上移动 html 元素位置缓慢
【发布时间】:2012-07-25 22:41:26
【问题描述】:

当我在 CSS 中修改多个 html 元素的位置时,我在 iOS html5 webapp 上遇到了一个巨大的性能问题。我还想手动移动我的元素。我不想使用 CSS 转换,因为无法停止动画(我们正在制作一个高度响应的游戏)。

我的示例在 Android 上的桌面浏览器(chrome、firefox 等)上运行良好。但它在 iPad 2 和 iPhone 4S(均运行 iOS 5.1)上非常慢。 在 Phonegap 应用程序中运行 html5 代码比直接在浏览器中运行要好,但仍然很慢。

您有什么改进建议?
editable example
full screen example

【问题讨论】:

  • 你有没有想过这个问题?这不是 jquery,iOS 和移动元素发生了一些事情......
  • @Kevin Nope。我放弃了这个项目并减少了资源消耗……我的结论是 html5 还没有为高性能游戏做好准备。

标签: javascript jquery css ios html


【解决方案1】:

首先,如果你想要一些不慢的东西,尽量避免所有的 jQuery 调用。

以下是我将如何(非常快地)重写您的代码:

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       || 
          window.webkitRequestAnimationFrame || 
          window.mozRequestAnimationFrame    || 
          window.oRequestAnimationFrame      || 
          window.msRequestAnimationFrame     || 
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();

var canvas = document.getElementById('canvas-test');
    canvas.height = 500;
    canvas.width = 500;
    var context = canvas.getContext('2d');

    // in this example, the fillstyle is always the same. no need to change it at every loop
    context.fillStyle = "#FF0000";


var balls = [];
var ballcanvas = [];
var ballctx = [];

// create 30 balls in canvases
var eDivBody = document.getElementById('divbody');
for (var i = 0; i < 30; i++){
    balls[i] = {
        x : 250,
        y : 100 + i * 2,
        dx : 3, // direction
    };

    // create the canvas
    var eBall = document.createElement('canvas');
    eBall.id = 'ballcanvas' + i;
    eBall.width = 75;
    eBall.height = 75;
    eDivBody.appendChild(eBall);

    // some css
    // no need for jQuery
    eBall.style.position = "absolute";
    eBall.style.left = balls[i].x + "px";
    eBall.style.top = balls[i].y + "px";
    eBall.style.backgroundColor = "#000000";

    // associate the element to the ball, no need to go threw the DOM after
balls[i].element = eBall;
}


var ball_test = {
    x : 250,
    y : 300,
    dx : 3 // direction
};


function loop(ball_test, balls, canvas, context, ballcanvas, ballctx){
    //change of direction on the sides
    if (ball_test.x > 400 || ball_test.x < 100)
        ball_test.dx *= -1;
    // movement
    ball_test.x += ball_test.dx;

    // the same for balls in canvases
    // never use array.legth in a loop condition. put it in a variable then compare. 
    for (var i = 0, j = balls.length; i < j; i++){
        // balls are following the test ball, no need to re-check the bounds
        // we take the test ball direction
        balls[i].dx =  ball_test.dx;

        //movement   
        balls[i].x += balls[i].dx;
        // change left style - No need for jQuery
        balls[i].element.style.left = balls[i].x + "px";
    }

    // display ball_test
    displayBallTest(ball_test, canvas, context);

    // Prefer the use of requestAnimationFrame
    requestAnimFrame(function(){
        loop(ball_test, balls, canvas, context, ballcanvas, ballctx);
    });
};

// no need to recalculate Math.PI * 2 for every loop.
// do it just the first time then use the value
var pi2 = Math.PI * 2;

function displayBallTest(ball, canvas, context){
    // clear canvas    
    // you don't need to clear all the canvas, just the zone where you now the ball is.
    // must need some calculation to be the most efficient possible
    context.clearRect(ball.x - 50 , ball.y  - 50, 100, 100);

    context.beginPath();
    context.arc(ball.x, ball.y, 40, 0, pi2 );
    context.fill();
};

// start main loop
loop(ball_test, balls, canvas, context, ballcanvas, ballctx);

我评论了代码,但这是我所做的:

  • 完全避免使用 jQuery。不需要,除非您选择不将脚本放在内容末尾,否则可能是为了准备就绪
  • 尽可能使用 requestAnimationFrame
  • 避免重新计算或重置全局值 (Math.PI*2 , context.fillStyle ...)
  • 避免使用 .length if for 循环条件

但我认为您的问题来自您想要移动 30 个画布元素而不是将它们的内容绘制到主画布中的事实。 众所周知,iOS 在您使用 Canvas 绘图时速度很快。 对我来说,如果您选择在主画布上绘制而不是移动 DOM 元素,您的性能问题将会得到解决。

【讨论】:

【解决方案2】:

您可以做的一件显而易见的事情是缓存您的选择器,而不是每次都执行它:

   // some css            
    $('#ballcanvas' + i).css("position", "absolute");
    $('#ballcanvas' + i).css("left", balls[i].x + "px");
    $('#ballcanvas' + i).css("top", balls[i].y + "px");
    $('#ballcanvas' + i).css("background-color", "#000000");

应该是这样的:

var thisBall = $('#ballcanvas' + i)
thisBall.css("position", "absolute");
... rest of your code ....

旁白:既然您已经拥有 Jquery $,为什么还要使用 document.getElementById

【讨论】:

  • 他不需要选择器。 $('#ballcanvas' + i) 是在之前创建的。他必须在 ballcanvas[i] 上行动。但这不是问题,因为这个函数只是初始化动画。问题来了。首先,在循环条件中使用.length。投反对票,因为当他要求快速时,您告诉他使用 jQuery。避免使用 jQuery 会是一个很好的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
相关资源
最近更新 更多