我有一个pannable应用程序窗口,通过监听mousemove
个事件然后使用transform: translate3d(...)
相应地移动屏幕来工作。它是一个大型应用程序,并且有相当多的UI工作可以促进此功能。 MCVE就在这里,其中实际工作负载由虚拟for
循环模拟:
var container = document.getElementById("container");
var contents = document.getElementById("contents");
var input = document.getElementById("iterations");
var posX = 50;
var posY = 50;
var previousX = null;
var previousY = null;
var mousedownHandler = function (e) {
window.onmousemove = globalMousemoveHandler;
window.onmouseup = globalMouseupHandler;
previousX = e.clientX;
previousY = e.clientY;
}
var globalMousemoveHandler = function (e) {
var now = Date.now();
for (var i = 0, n = parseInt(input.value); i < n; i++);
var elapsed = Date.now() - now;
posX += e.clientX - previousX;
posY += e.clientY - previousY;
previousX = e.clientX;
previousY = e.clientY;
contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
contents.innerText = elapsed + "ms";
}
var globalMouseupHandler = function (e) {
window.onmousemove = null;
window.onmouseup = null;
previousX = null;
previousY = null;
}
container.onmousedown = mousedownHandler;
contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
#container {
height: 180px;
width: 600px;
background-color: #ccc;
overflow: hidden;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
#container:active {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
<label>Iterations: <input id="iterations" type="number" value="20000000" step="5000000" /></label>
<div id="container">
<div id="contents">
Pannable container contents...
</div>
</div>
JSFiddle example with larger drag-area
请按住并拖动示例。
每次for
触发时,此基本代码段都会运行一个虚拟mousemove
循环,循环完成所需的持续时间将显示在可拖动容器中。这需要证明下面的问题。您可能需要调整迭代次数,以便循环运行时间超过10ms,但不会太长。
此代码段在Google Chrome中尽可能快地运行,没有任何问题。在Firefox中未经测试。
但是,如果globalMousemoveHandler
运行时间超过10毫秒,则在Microsoft Edge (可能还有IE11)中,浏览器开始重新限制事件,使其频繁发生火灾,并将平移进度消除在爬行中。
同样奇怪的是,for
循环实际上在Microsoft Edge中运行更快比在Chrome中运行速度快得多(几乎快50%),但该事件仍会激活很多不那么频繁。
从上述浏览器中查看时,可以在上面的代码段中观察到这一点。现在我理解了这个功能背后的理论需求,但是它在我的浏览器中呈现了我的应用程序不可用 - 我也真的不明白在16ms 之下启动限制的重点是什么?我完全不在60 FPS预算范围内,但现在除了现在的问题(虽然我很高兴听到有关此事的一些细节)。
如何防止这种情况发生?
答案 0 :(得分:4)
以下是使用requestAnimationFrame的示例。
var container = document.getElementById("container");
var contents = document.getElementById("contents");
var input = document.getElementById("iterations");
var posX = 50;
var posY = 50;
var previousX = null;
var previousY = null;
var mousedownHandler = function (e) {
window.onmousemove = globalMousemoveHandler;
window.onmouseup = globalMouseupHandler;
previousX = e.clientX;
previousY = e.clientY;
}
var globalMousemoveHandler = function (e) {
posX += e.clientX - previousX;
posY += e.clientY - previousY;
previousX = e.clientX;
previousY = e.clientY;
window.requestAnimationFrame(function () {
var now = Date.now();
for (var i = 0, n = parseInt(input.value); i < n; i++);
var elapsed = Date.now() - now;
contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
contents.innerText = elapsed + "ms";
});
}
var globalMouseupHandler = function (e) {
window.onmousemove = null;
window.onmouseup = null;
previousX = null;
previousY = null;
}
container.onmousedown = mousedownHandler;
contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
&#13;
#container {
height: 180px;
width: 600px;
background-color: #ccc;
overflow: hidden;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
#container:active {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
&#13;
<label>Iterations: <input id="iterations" type="number" value="20000000" step="5000000" /></label>
<div id="container">
<div id="contents">
Pannable container contents...
</div>
</div>
&#13;
这可以阻止繁重的阻止处理程序功能,有效防止问题的发生,代价是延迟增加16ms。