功能完成时间比预期的要长

时间:2016-09-04 03:27:44

标签: javascript

我创建了一个简单的滑动函数,它可以使元素在给定的时间内出现或消失。

我建立此功能的公式是: ms = 1 pixel / (initial size / duration) ,基本上计算在从元素 1px 之前应经过多少毫秒> height width

我的数学逻辑表示该功能应该在 1000ms 中完成,但对我来说,完成外观所花费的时间要多得多,而不确定是多少。

为什么需要比 1s 更长的时间才能完成以及可能导致它的原因?

代码:

/* ----- JavaScript ----- */
function slide(el, duration, direction) {
  /* Default */
  duration = duration || 1000, direction = direction || "vertical";

  var
    dim = (direction === "horizontal") ? "width" : "height",
      
    /* Get how tall or wide el is in 'px' */
    size = initSize = parseFloat(
      getComputedStyle(el, null).getPropertyValue(dim) || el.style[dim]
    ),
      
    /* Get the previous size, so as to restore el to it */
    prevSize = el.style["prev" + dim] || 0,
      
    /* Calculating how many ms should pass before subtracting 1px*/
    ms = 1 / (initSize / duration),
      
    interval = setInterval(function() {
      /* If el is visible */
      if (initSize > prevSize && size > prevSize) el.style[dim] = --size + "px";
      
      /* If el is not visible */
      else if (prevSize > initSize && size <= prevSize) el.style[dim] = ++size + "px";
      
      /* Clear the interval when 0 is reached and cache the previous size */
      else {
        console.log("oops")
        el.style["prev" + dim] = initSize;
        clearInterval(interval);
      }
    }, ms);
}

slide(document.getElementById("a"));
<!----- HTML ----->
<div id = "a" style = "width: 200px;height: 300px;background-color:black;"></div>

2 个答案:

答案 0 :(得分:1)

您需要调整步长,即每次迭代要添加/删除的像素数,并调整延迟时间。以下是一个改进的版本,大约需要1.1秒。

function slide(el, duration, direction) {
  /* Default */
  duration = duration || 1000, direction = direction || "vertical";

  var dim = (direction === "horizontal") ? "width" : "height",

    /* Get how tall or wide el is in 'px' */
    size = initSize = parseFloat(
      getComputedStyle(el, null).getPropertyValue(dim) || el.style[dim]
    ),

    /* Get the previous size, so as to restore el to it */
    prevSize = el.style["prev" + dim] || 0;

    /* Calculating how many ms should pass before subtracting 1px*/
    var step = 1;
     var ms = 1 / (initSize / duration)
    if(ms<10){
        ms=10;
        step = 10*(initSize/duration);
        console.log(ms,step)
    }
      var now=new Date();
      var interval;var i=0;
    var animate = function() {
    i++;
        interval=setTimeout(animate,ms);
      /* If el is visible */
      if (initSize > prevSize && size > prevSize) el.style[dim] = (size=size-step) + "px";

      /* If el is not visible */
      else if (prevSize > initSize && size <= prevSize) el.style[dim] = (size=size+step) + "px";

      /* Clear the interval when 0 is reached and cache the previous size */
      else {
        console.log("oops", new Date()-now,size,step,i)
        el.style["prev" + dim] = initSize;
        clearInterval(interval);
      }
    };
    //var interval = setInterval(animate, ms);
    animate();
}
slide(document.getElementById("a"));

答案 1 :(得分:1)

在阅读了Jaromanda X的评论后,我终于使用了 window.requestAnimationFrame() ,因为它比 setInterval() 更有效率它也不会强制浏览器重绘。

这反过来让我将我的公式从时间导向( ms = 1 / (initial size / duration) )更改为像素导向( px = frame * (initial size / duration) )。

现在滑动更顺畅,非常接近 1000ms ,我认为只有 5-7ms 差异,因为我设置了 frame 变量 1000 / 60 未考虑可能发生的帧速率下降。

<强>代码:

/* ----- JavaScript ----- */
function slide(el, duration, direction) {
  /* Set Defaults and record starting date */
  var a = Date.now();
  duration = duration || 1000, direction = direction || "vertical";

  var
    dim = (direction === "horizontal") ? "width" : "height",

    /* Get how tall or wide el is in 'px' */
    size = initSize = parseFloat(
      getComputedStyle(el, null).getPropertyValue(dim) || el.style[dim]
    ),

    /* Get the previous size, so as to restore el to it */
    prevSize = el.style["prev" + dim] || 0,

    /* Calculating how many px should be added / subtracted each frame */
    frame = 1000 / 60,
    px = frame * (initSize / duration),
    step = (initSize > prevSize) ? -px : px;

  window.requestAnimationFrame(function transform() {
    el.style[dim] = (size > 0) ? (size += step) + "px" : (size = 0);
    if (size === 0) {
      el.style["prev" + dim] = initSize;
      //element.style.prevDisplay = initDisplay;
      console.log(Date.now() - a)
    } else window.requestAnimationFrame(transform);
  }, frame);
}

slide(document.getElementById("a"), 1000);
<!----- HTML ----->
<div id="a" style="width: 200px;height: 300px;background-color:black;"></div>