Skip to content

ES6 - 动画

JavaScript 可以通过随着时间动态改变 DOM 元素的属性来创建网页动画。这可以从简单的移动和淡入淡出效果,扩展到更复杂的序列动画。虽然对于许多常见效果来说,CSS Animations 和 Transitions 在性能和简单性方面通常更受欢迎,但 JavaScript 为复杂的程序化动画提供了更大的控制。

JavaScript 提供了对于动画至关重要的定时函数:

  • setTimeout(callbackFunction, delayInMilliseconds): 在指定的 delayInMilliseconds 后执行一次 callbackFunction。
  • setInterval(callbackFunction, intervalInMilliseconds): 每隔指定的 intervalInMilliseconds 重复执行 callbackFunction。
  • clearTimeout(timeoutID): 取消之前通过调用 setTimeout() 建立的定时器。timeoutID 是 setTimeout() 返回的值。
  • clearInterval(intervalID): 取消之前通过调用 setInterval() 建立的定时重复动作。intervalID 是 setInterval() 返回的值。
  • requestAnimationFrame(callbackFunction): 告知浏览器您希望执行动画,并请求浏览器在下一次页面重绘之前调用指定的函数来更新动画。这是 JavaScript 驱动动画的首选方法,因为它针对平滑性和电池续航进行了优化。

动画通常是通过随着时间改变元素的 CSS 属性来实现的,例如 left、top、opacity、transform 等等。

// Set distance from left edge (assuming position is 'absolute', 'relative', or 'fixed')
// 设置与左边缘的距离(假设 position 为 'absolute', 'relative', 或 'fixed')
// object.style.left = '100px';
// Set opacity for fade effects
// 设置 opacity 用于淡入淡出效果
// object.style.opacity = '0.5';

此示例展示了如何在每次点击按钮时将图片向右移动。

<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript Manual Animation</title>
<style>
#myImage { position: relative; left: 0px; top: 0px; transition: left 0.5s ease; /* Optional: for smoother visual transition */ /* 可选:为了更平滑的视觉过渡 */}
</style>
</head>
<body>
<img id="myImage" src="https://via.placeholder.com/50" alt="Placeholder Image">
<p>Click button below to move the image to the right.</p>
<button id="moveButton">Move Right</button>
<script>
const imgObj = document.getElementById('myImage');
const moveButton = document.getElementById('moveButton');
// Ensure the element's style.left is initialized if not set by CSS
// Or parse it assuming it's '0px' initially
// 如果 CSS 没有设置,确保元素 style.left 已初始化
// 或者假设它初始为 '0px' 进行解析
imgObj.style.left = imgObj.style.left || '0px';
function moveRight() {
let currentLeft = parseInt(imgObj.style.left, 10); // Parse the current left value // 解析当前的 left 值
imgObj.style.left = (currentLeft + 20) + 'px'; // Increment and set // 增加并设置
}
moveButton.addEventListener('click', moveRight);
// Initialize position via JS if needed if not using inline styles or CSS for initial state
// 如果不使用内联样式或 CSS 设置初始状态,则需要通过 JS 初始化位置
// window.onload = () => { imgObj.style.left = '0px'; }; // Example initialization // 示例初始化
</script>
</body>
</html>

输出描述:

显示一张图片。每次点击“Move Right”按钮,图片会从当前位置向右移动 20 像素。添加 CSS transition(如 <style> 块中所示)可以使这种移动看起来更平滑。

使用 requestAnimationFrame 的自动化动画

Section titled “使用 requestAnimationFrame 的自动化动画”

对于连续动画,requestAnimationFrame 是最佳选择。它与浏览器的刷新率同步,从而产生更平滑的动画和更好的性能。

<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript Automated Animation</title>
<style>
#animatedBox {
position: relative; left: 0px;
width: 50px; height: 50px; background-color: dodgerblue;
}
</style>
</head>
<body>
<div id="animatedBox"></div>
<p>Click buttons below to handle animation.</p>
<button id="startButton">Start</button>
<button id="stopButton">Stop</button>
<script>
const box = document.getElementById('animatedBox');
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
let animationId = null; // To store the ID from requestAnimationFrame // 用于存储 requestAnimationFrame 返回的 ID
function animateBox() {
let currentLeft = parseInt(box.style.left || '0px', 10);
if (currentLeft > 300) { // Move back to start if it goes too far // 如果移动太远,回到起点
currentLeft = 0;
}
box.style.left = (currentLeft + 2) + 'px';
animationId = requestAnimationFrame(animateBox); // Continue the animation // 继续动画
}
startButton.addEventListener('click', function() {
if (!animationId) { // Start only if not already running // 仅在动画未运行时启动
box.style.left = '0px'; // Reset position before starting // 启动前重置位置
animationId = requestAnimationFrame(animateBox);
}
});
stopButton.addEventListener('click', function() {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null; // Reset the ID // 重置 ID
}
});
</script>
</body>
</html>

输出描述:

显示一个蓝色方块。点击“Start”会使方块持续向右移动。如果它到达某个点(300px),它会重置回左边并继续移动。点击“Stop”会停止动画。使用 requestAnimationFrame 可以实现平滑的循环。

一种常见的交互效果是在鼠标指针悬停在图片上时改变图片。

<!DOCTYPE html>
<html lang="en">
<head>
<title>Image Rollover</title>
</head>
<body>
<p>Move your mouse over the image:</p>
<img id="rolloverImage" src="https://via.placeholder.com/150/FF0000/FFFFFF?Text=Image1" alt="Image 1">
<script>
const image = document.getElementById('rolloverImage');
const originalSrc = image.src;
const hoverSrc = 'https://via.placeholder.com/150/0000FF/FFFFFF?Text=Image2'; // Different image for hover // 悬停时显示不同的图片
// Preload hover image for better user experience
// 预加载悬停图片以获得更好的用户体验
const preloadHoverImage = new Image();
preloadHoverImage.src = hoverSrc;
image.addEventListener('mouseover', function() {
image.src = hoverSrc;
});
image.addEventListener('mouseout', function() {
image.src = originalSrc;
});
</script>
</body>
</html>

输出描述:

显示一张初始图片(Image1,红色占位符)。当用户将鼠标指针移到此图片上时,图片会变为另一张不同的图片(Image2,蓝色占位符)。当鼠标移开时,图片会恢复为原始图片。预加载悬停图片可确保在需要时立即可用。

对于许多动画,尤其是不严重依赖复杂 JavaScript 逻辑的动画,可以考虑使用:

  • CSS Transitions: 在给定持续时间内平滑地动画化 CSS 属性的变化。
  • CSS Animations: 允许完全在 CSS 中定义更复杂的、基于关键帧 (Keyframes) 的动画。
  • Web Animations API (WAAPI): 一个 JavaScript API,提供对动画更直接的控制,结合了 JavaScript 的强大功能和浏览器优化动画的性能优势。对于复杂场景,它是基于 setTimeout/setInterval 的动画的一种更现代、更强大的替代方案。

选择合适的工具取决于动画的复杂性和所需的控制级别。