Javascript move 元素与鼠标移动事件 60 FPS 请求动画帧
Javascript move element with mousemove event 60 FPS requestAnimationFrame
那里! 我有一个问题#drag
让元素顺利移动。
我看这篇文章:http://www.html5rocks.com/en/tutorials/speed/animations/#debouncing-mouse-events
它说:"当移动元素时mousemove
事件的问题是鼠标移动事件触发太多
所以,我尝试使用他们的方法:使用 requestAnimationFrame
+ boolean checking
.
看看这个真人小提琴:https://jsfiddle.net/5f181w9t/
.HTML:
<div id="drag">this is draggable</div>
.CSS:
#drag {width:100px; height:50px; background-color:red; transform:translate3d(0, 0, 0); }
.JS:
var el = document.getElementById("drag"),
startPosition = 0, // start position mousedown event
currentPosition = 0, // count current translateX value
distancePosition = 0, // count distance between "down" & "move" event
isMouseDown = false; // check if mouse is down or not
function mouseDown(e) {
e.preventDefault(); // reset default behavior
isMouseDown = true;
startPosition = e.pageX; // get position X
currentPosition = getTranslateX(); // get current translateX value
requestAnimationFrame(update); // request 60fps animation
}
function mouseMove(e) {
e.preventDefault();
distancePosition = (e.pageX - startPosition) + currentPosition; // count it!
}
function mouseUp(e) {
e.preventDefault();
isMouseDown = false; // reset mouse is down boolean
}
function getTranslateX() {
var translateX = parseInt(getComputedStyle(el, null).getPropertyValue("transform").split(",")[4]);
return translateX; // get translateX value
}
function update() {
if (isMouseDown) { // check if mouse is down
requestAnimationFrame(update); // request 60 fps animation
}
el.style.transform = "translate3d(" + distancePosition + "px, 0, 0)";
// move it!
}
el.addEventListener("mousedown", mouseDown);
document.addEventListener("mousemove", mouseMove);
document.addEventListener("mouseup", mouseUp);
这是正确的伴奏方式吗?
我的代码有什么问题?
谢谢
问题是您在mouseDown
事件侦听器中使用requestAnimationFrame()
。您应该在mouseMove
事件侦听器中执行所有更新,因为您希望在鼠标移动时更新显示,而不是在鼠标单击时更新显示。因此,您应该在 update
函数中isMouseDown
条件下更新所有变量。我建议按如下方式更正代码。
var el = drag,
startPosition = 0, // start position mousedown event
currentPosition = 0, // count current translateX value
distancePosition = 0, // count distance between "down" & "move" event
isMouseDown = false, // check if mouse is down or not
needForRAF = true; // to prevent redundant rAF calls
function mouseDown(e) {
e.preventDefault(); // reset default behavior
isMouseDown = true;
currentPosition = getTranslateX(); // get current translateX value
startPosition = e.clientX; // get position X
}
function mouseMove(e) {
e.preventDefault();
distancePosition = (e.clientX - startPosition) + currentPosition; // count it!
if (needForRAF && isMouseDown) {
needForRAF = false; // no need to call rAF up until next frame
requestAnimationFrame(update); // request 60fps animation
}
}
function mouseUp(e) {
e.preventDefault();
isMouseDown = false; // reset mouse is down boolean
}
function getTranslateX() {
var translateX = parseInt(getComputedStyle(el, null).getPropertyValue("transform").split(",")[4]);
return translateX; // get translateX value
}
function update() {
needForRAF = true; // rAF now consumes the movement instruction so a new one can come
el.style.transform = "translateX(" + distancePosition + "px)"; // move it!
}
el.addEventListener("mousedown", mouseDown);
document.addEventListener("mousemove", mouseMove);
document.addEventListener("mouseup", mouseUp);
#drag {
width: 100px;
height: 50px;
background-color: red;
transform: translateX(0);
}
<div id="drag">this is draggable</div>
在这里查看。
您的代码应该已经可以正常工作了。但是,这是另一种方法:
您需要确保每帧只允许一个requestAnimationFrame
调用通过,否则update()
将在下一个repaint
被多次调用,这可能会导致延迟并降低您的 fps。为此,您需要保存请求的帧,并在每个mousemove
事件上检查是否已有一个帧对齐。如果有,您需要使用 cancelAnimationFrame
取消它并提出新请求。这种方式update()
仅在浏览器能够呈现更改的频率(即大多数浏览器中为 60fps)时才调用。
function mouseDown(e) {
e.preventDefault(); // cancel default behavior
isMouseDown = true;
startPosition = e.pageX; // get position X
currentPosition = getTranslateX(); // get current translateX value
}
var lastUpdateCall=null;
function mouseMove(e){
if(isMouseDown){ //check if mousedown here, so there aren't any unnecessary animation frame requests when the user isn't dragging
e.preventDefault(); // You probably only want to preventDefault when the user is actually dragging
if(lastUpdateCall) cancelAnimationFrame(lastUpdateCall); //if an animation frame was already requested after last repaint, cancel it in favour of the newer event
lastUpdateCall=requestAnimationFrame(function(){ //save the requested frame so we can check next time if one was already requested
distancePosition = (e.clientX - startPosition) + currentPosition; // Do the distance calculation inside the animation frame request also, so the browser doesn't have to do it more often than necessary
update(); //all the function that handles the request
lastUpdateCall=null; // Since this frame didn't get cancelled, the lastUpdateCall should be reset so new frames can be called.
});
}
}
function update(){
el.style.transform = "translateX(" + distancePosition + "px)";// move it!
}
如果没有null
,您也可以不再调用requestAnimationFrame
lastUpdateCall
但这意味着您必须在每次event
触发时计算动画帧调用之外的距离,否则动画将落后于鼠标长达 20 毫秒。 我想这两种方法都可以。
- ajax请求的顺序总是不同的
- Meteor如何接收HTTP请求
- 有没有一种方法可以防止img get请求使用css或js发生
- 从ajax请求中获取javascript对象
- JSONP请求返回结果,但也触发error_callback
- 在localhost Dev Box上测试JSONP请求的最佳方式
- Ajax请求文档就绪会导致jquery加载缓慢
- MockJax没有在JavaScript应用程序中发送对我AJAX请求的响应
- 正在传递JSONP标头's数据参数到另一个文件中的AJAX请求
- 在openshift node js应用程序中获取请求
- 反应路由器弄乱了请求网址
- 在我的情况下,如何进行http请求
- 使用密码对话框Javascript请求帮助
- servlet中的请求对象,而不是从jsp接收参数值
- 否'访问控制允许来源'标头存在于IISNOde中请求的资源(AngularJS+NodeJs)上
- JavaScript代码未正确检查ajax请求
- node.js请求数据事件未在CORS ajax调用中触发
- 如何检测第三方广告服务器请求
- 在Rails中更新Div,而不更改更新请求后的视图
- Javascript move 元素与鼠标移动事件 60 FPS 请求动画帧