我正在编写一个小程序,我以指定的速度移动DOM
。
当我以20px per second
的速度移动时,添加到offset
的{{1}}约为elem.style.top
。
问题是,当0.3px per frame
小于offset
时,0.5px
无法移动!
我构建了一个简化的示例,可以在我的程序中演示该问题:
elem

var requestFrameAnimationId;
function myMove(offset) {
var elem = document.getElementById("animate");
requestFrameAnimationId = animationLoop(frame);
function frame() {
console.log(elem.offsetTop);
if (elem.offsetTop === 350) {
cancelAnimationFrame(requestFrameAnimationId);
} else {
elem.style.top = elem.offsetTop + offset + 'px';
elem.style.left = elem.offsetLeft + offset + 'px';
}
}
}
function animationLoop(render) {
var running, lastFrame = +new Date(); // casting Date to Number
function loop(now) {`enter code here`
requestFrameAnimationId = requestAnimationFrame(loop);
running = render(now - lastFrame);
lastFrame = now;
}
loop(lastFrame);
}

#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}

尝试点击<!DOCTYPE html>
<html>
<body>
<p>
<button onclick="myMove(0.3)">Move at 0.3px per frame</button>
<button onclick="myMove(0.5)">Move at 0.5px per frame</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
</body>
</html>
。矩形应该移动。
点击Move at 0.5px per frame
重置它。
现在尝试点击Run code snippet
。
它应该更慢地移动DOM,但你可以看到DOM没有移动。
这很奇怪,因为当我最初跟踪javascript变量Move at 0.3px per frame
中的top
位置,并将topPos
应用于${topPos + offset}
时,它在甚至更慢的速度!
所以我的猜测是elem.style.top
舍入小数值,因此0.3变为0,0.5变为1。
我可以做些什么来让DOM以指定的速度精确移动?我无法使用任何库。
编辑:我更深入地研究了这个问题,我相信它是elem.offsetTop
将数字四舍五入为整数。
但是,我发现CSS OM规范将offsetTop
的类型更改为offsetTop
和the Chromium team was working on applying the change on the browser more than 4 years ago, and it seems that it should be fixed by now。
为什么它不能用于我的程序,我怎样才能使它工作?
EDIT2:我从CSSOM working draft发现float
的类型是整数。
offsetTop
我认为他们只将readonly attribute long offsetTop;
和scrollTop
的类型更改为双精度数。
scrollLeft
答案 0 :(得分:2)
HTMLElement.offset[Left | Top]返回long
类型值(即整数)。
如果您想要浮动值,请使用Element.getBoundingClientRect。
var requestFrameAnimationId;
function myMove(offset) {
var elem = document.getElementById("animate");
requestFrameAnimationId = animationLoop(frame);
function frame() {
// build up our own high precision offsetTop
var parentRect = elem.offsetParent && elem.offsetParent.getBoundingClientRect() || {top: 0, left:0};
var elemRect = elem.getBoundingClientRect();
var rect = {
top: elemRect.top - parentRect.top,
left: elemRect.left - parentRect.left
};
if (rect.top >= 350) {
cancelAnimationFrame(requestFrameAnimationId);
} else {
// so we can substract it here
elem.style.top = (rect.top + offset) + 'px';
elem.style.left = (rect.left + offset) + 'px';
}
}
}
function animationLoop(render) {
var running, lastFrame = +new Date(); // casting Date to Number
function loop(now) {
requestFrameAnimationId = requestAnimationFrame(loop);
running = render(now - lastFrame);
lastFrame = now;
}
loop(lastFrame);
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove(0.3)">Move at 0.3px per frame</button>
<button onclick="myMove(0.5)">Move at 0.5px per frame</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
或者只是将您的值加到变量中:
var requestFrameAnimationId;
function myMove(offset) {
var elem = document.getElementById("animate");
requestFrameAnimationId = animationLoop(frame);
var pos = 0;
function frame() {
pos += offset;
if (pos >= 350) {
cancelAnimationFrame(requestFrameAnimationId);
} else {
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function animationLoop(render) {
var running, lastFrame = +new Date(); // casting Date to Number
function loop(now) {
requestFrameAnimationId = requestAnimationFrame(loop);
running = render(now - lastFrame);
lastFrame = now;
}
loop(lastFrame);
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove(0.3)">Move at 0.3px per frame</button>
<button onclick="myMove(0.5)">Move at 0.5px per frame</button>
</p>
<div id="container">
<div id="animate"></div>
</div>