本节将学习如何添加实时动画。例如,在页面上从左到右移动 <div> 类型元素。
这个 <div> 将显示为红色,并且在页面加载时,从左到右地移动。
#frame {
border: 1px solid red;
}
#block {
width: 20px;
height: 40px;
background: red;
position: relative;
}
<html>
<head>
</head>
<body>
<div id="frame">
<div id="block"></div>
</div>
</body>
</html>
显示效果如下:
开始动画
示例代码定义了一个名为 moveBlock() 的函数,它将块水平地向右移动。它获取左边框的当前位置,然后添加包含在移动变量中的值。接下来,代码调用 requestAnimationFrame() 方法来继续动画。
位置以像素值表示。单位是 "px",它要求在进行计算之前使用 JavaScript 的 parseFloat() 函数转换数值。
注意:不要使用 Number() 将带有 "px" 的字符串转换为数值,你将会得到一个 NaN值(不是一个数字)作为结果。
requestAnimationFrame() 函数允许您请求浏览器尽快执行一个函数,该函数将更新动画。让动画尽可能流畅是浏览器的工作。requestAnimationFrame() 的返回值是动画的一个 ID,可以用来进一步修改它。
下面是 requestAnimationFrame()函数与动画功能结合使用的方法:
const animate = () => {
// Animation code
// ...
// At end of animation, request another one
animationId = requestAnimationFrame(animate);
};
// Animation start
let animationId = requestAnimationFrame(animate);
停止动画
现在,让我们看看如何在块到达包含它的帧的边界之前停止它。我们必须验证左边框位置小于框架的宽度,同时要考虑到块本身的厚度。
以下是更新后的代码:
// Move the block to the right, all the way to the end of the frame
const moveBlock = () => {
// Convert the left position of the block (value of the form "XXpx") to a number
const xBlock = parseFloat(getComputedStyle(blockElement).left);
// Convert the width of the frame (value of the form "XXpx") to a number
const xMax = parseFloat(getComputedStyle(frame).width);
// If the block isn't already to the end of the frame
if (xBlock + blockWidth <= xMax) {
// Block movement
blockElement.style.left = (xBlock + movement) + "px";
animationId = requestAnimationFrame(moveBlock);
}
else {
// Cancel the animation
cancelAnimationFrame(animationId);
}
};
const blockElement = document.getElementById("block");
// Convert the block width (value of the form "XXpx") to a number
const blockWidth = parseFloat(getComputedStyle(block).width);
// Movement value in pixels
const movement = 7;
// Start the animation
let animationId = requestAnimationFrame(moveBlock);
新的 moveBlock() 函数在进一步移动之前检查该快是否已经到达帧的末尾。在这种情况下,动画通过调用 cancelAnimationFrame() 停止。cancelAnimationFrame() 函数停止动画,并获取之前调用 requestAnimationFrame() 所设置的动画的 ID。
使用方法如下:
// Stop an animation
cancelAnimationFrame(animationID);
替代方案:使用CSS实现上面的动画
<html>
<head>
</head>
<body>
<div id="frame">
<div id="block"></div>
</div>
</body>
</html>
#frame {
border: 1px solid red;
}
#block {
width: 20px;
height: 40px;
background: red;
position: relative;
margin-left: -20px; /* Negative margin to simplify position calculations */
animation-name: moveBlock; /* Name of animation */
animation-duration: 6s; /* Length of animation */
animation-fill-mode: forwards; /* Let the block in its final position */
}
@keyframes moveBlock {
from {
/* Initial position: to the left of the frame (taking negative margin into account) */
left: 20px;
}
to {
/* Final position: within the right side of the frame (taking negative margin into account) */
left: 100%;
}
}
如何选择正确的方式添加动画
如何选择 setInterval() ,requestAnimationFrame() 或 CSS 来添加动画呢?答案取决于你的动画有多复杂。理论上,CSS 动画在性能方面更高效,但你不能用它们做所有的事情。
- 如果动画不是实时的,并且应该定期发生,则使用 setInterval()。
- 如果动画是实时的,并且可以用它来管理,那就使用 CSS。
- 在任何其他情况下使用 requestAnimationFrame()。