requestAnimationFrame在显示确认对话框时给出了错误的时间戳(Chromium?)

问题描述 投票:1回答:1

我有一个简单的动画,使用requestAnimationFrame完成(为了演示目的改编自the example on MDN)。如果在动画之前我显示了confirm对话框,则动画函数接收的时间戳是错误的。第一个和第二个时间戳之间的差异等于从显示confirm消息的那一刻起,直到单击“确定”按钮为止。这种行为(错误?)在Chrome和Opera中都可见(两者都运行Chromium)。 Firefox和Internet Explorer 11按预期运行。检查the fiddle或以下示例。

const cache = {
  start: null,
  target: null
};

function animate(timestamp) {
  console.log(timestamp);
  if (cache.start === null) {
    cache.start = timestamp;
  }
  var progress = timestamp - cache.start;
  cache.target.style.left = Math.min(progress / 10, 100) + 'px';
  if (progress < 1000) {
    requestAnimationFrame(animate);
  } else {
    cache.target.style.left = 0;
    cache.start = null;
  }
}

(function() {
  const target = document.getElementsByTagName("div")[0];
  cache.target = target;
  const cb = document.getElementsByTagName("input")[0];

  const btn = document.getElementsByTagName("button")[0];
  btn.addEventListener("click", function() {
    if (cb.checked) {
      if (confirm("Just click 'OK' to start the animation, ok?")) {
        requestAnimationFrame(animate);
      }
    } else {
      requestAnimationFrame(animate);
    }
  })
})();
html,
body {
  padding: 0;
  margin: 0;
}

div {
  width: 50px;
  height: 50px;
  border: 1px solid black;
  background-color: yellowgreen;
  position: absolute;
  top: 50px;
}

button {
  margin-top: 20px;
}
<button type="button">Start</button>
<label>
  <input type="checkbox" />use "confirm"</label>
<div>

</div>

打开控制台以查看收到的时间戳。动画设置为运行2秒。显示confirm对话框时,如果单击“确定”按钮的时间超过2秒,则动画将运行“剩余”时间。如果单击“确定”按钮所需的时间比动画时间长,则元素将不会被动画,并且将有2个值(时间戳)发送到控制台;这两个值的差异是单击“确定”按钮所需的时间。

我认为这是Chromium中的一个错误。有没有解决方法(仍然使用requestAnimationFrame动画,而不是通过CSS)?我在他们的追踪器中找不到任何相关内容。有没有人有这方面的其他信息?

javascript animation chromium
1个回答
1
投票

我不得不说,我发现这非常有趣。

花了很多时间后,我可能已经为你找到了解决方法。你可以在这看到。 https://jsfiddle.net/qtj467n0/13/

它的基本要点是,我取代了DOMHighResTimeStamp提供的requestAnimationFrameperformance.now(),它也返回了DOMHighResTimeStamp

const cache = {
  start: null,
  target: null,
  time: 2000
};

function animate(timestamp) {
  console.log(timestamp);
  if (cache.start === null) {
    cache.start = timestamp;
  }
  var progress = timestamp - cache.start;
  cache.target.style.left = Math.min(progress / 10, cache.time / 10) + 'px';
  if (progress < cache.time) {
    requestAnimationFrame(animate);
  } else {
    cache.target.style.left = 0;
    cache.start = null;
  }
}

const render = () => {

  requestAnimationFrame((timestamp) => {

    const performanceNow = performance.now();

    animate(performanceNow)
  });
}

(function() {
  const target = document.getElementsByTagName("div")[0];
  cache.target = target;
  const cb = document.getElementsByTagName("input")[0];


  const btn = document.getElementsByTagName("button")[0];
  btn.addEventListener("click", function() {
    if (cb.checked) {
      const confirmed = confirm("Just click 'OK' to start the animation, ok?");
      if (confirmed) {
        render();
      }
    } else {
      requestAnimationFrame(animate);
    }
  })
})();
html,
body {
  padding: 0;
  margin: 0;
}

div {
  width: 50px;
  height: 50px;
  border: 1px solid black;
  background-color: yellowgreen;
  position: absolute;
  top: 50px;
}

button {
  margin-top: 20px;
}
<button type="button">Start</button>
<label>
  <input type="checkbox" />use "confirm"</label>
<div>

</div>
© www.soinside.com 2019 - 2024. All rights reserved.