Anime.js:超好用的JavaScript动画库

在网页开发领域,动画是吸引用户的关键要素。anime.js 作为一款强大的 JavaScript 动画库,为开发者提供了便捷且高效的动画制作解决方案。
并且,最近发布了新版本,4.0.0,带来了诸多新特性和改进。接下来,我们将深入探讨anime.js的强大功能。
一、anime.js 简介
anime.js 是由 Julian Garnier 开发的轻量级 JavaScript 动画库,旨在帮助开发者轻松创建美观的动画效果。它支持对网页上的 DOM 元素、SVG 图形以及 CSS 属性进行动画处理。
二、anime.js 的特性
(一)简洁的语法
若要在 1 秒钟内,将 id 为 “myElement” 的元素从不透明变为完全透明,代码如下:
animate('myElement',{
opacity: [0, 1],
duration: 1000
});
该语法简洁明了,即便刚接触 JavaScript 动画的新手也能迅速理解。
(二)多目标与多属性动画
假设网页上存在多个 class 为 “box” 的元素,要同时将它们的宽度和高度变为 200 像素,代码可写作:
animate('.box',{
width: 200,
height: 200,
duration: 800
});
此外,anime.js 允许在一个动画序列中同时处理一个元素的多个属性。
(三)丰富的缓动函数
缓动函数对动画的自然流畅性起着重要作用。anime.js 内置了多种缓动函数,包括线性、缓入、缓出、缓入缓出以及各类复杂的缓动曲线。例如,为使元素在移动到指定位置时产生弹跳效果,代码如下:
animate('bounceElement'{
top: '200px',
duration: 1000,
easing: 'easeOutBounce'
});
通过这些缓动函数,动画效果更贴近现实中的物体运动。
(四)时间轴功能
anime.js 的时间轴功能类似于电影拍摄时对场景顺序的安排。它可将多个动画按顺序排列,每个动画可设置不同的延迟时间和持续时间。比如,先让一个元素从左向右移动,一段时间后,让另一个元素从上向下移动,代码如下:
var tl = createTimeline();
tl.add('element1',{
translateX: '100px',
duration: 800
})
tl.add('element2',{
translateY: '100px',
duration: 800,
delay: 400
});
借助时间轴功能,开发者能够更好地掌控动画流程,创作出更复杂、精彩的动画效果。
三、anime.js 的应用场景
(一)网页设计与 UI/UX
在网页设计中,可利用 anime.js 实现网页导航菜单的平滑展开或收起效果,增强用户交互体验。当用户鼠标悬停在按钮上时,也可通过 anime.js 对按钮的大小、颜色或透明度进行动态调整,给予用户及时反馈。
(二)数据可视化
对于数据可视化工作,anime.js 同样大有用处。例如,在数据加载时,可让柱状图的柱子逐一缓慢增长,或使折线图的线条随时间逐步绘制出来,使原本静态的图表变得生动,便于用户理解数据变化趋势。
(三)交互式网页故事创作
在创作交互式网页故事时,anime.js 能够使故事中的角色、背景以及文字元素动起来,增强故事的沉浸感,让用户仿佛身临其境。
四、实现一个demo
我们先来创建一个简单的demo,通过anime.js实现一个简单的动画效果。
TIP
移动端的设备不支持鼠标监听,如果有兴趣可以实现触摸监听。
效果:
描述:
这是一个简单的眼球追踪动画,当鼠标移动时,眼球会跟随鼠标移动。
实现思路:
- 使用
div
元素创建眼睛和瞳孔; - 利用CSS进行样式设计;
- 通过JavaScript监听鼠标的移动事件,并计算瞳孔的位置;
- 使用anime.js实现平滑的过渡效果。
源码:
这里引入方式是cdn,因为我需要尽可能的避免这个第三方库干扰我的博客体积。实际应用中,我更推荐你使用npm安装,这样可以更方便一点。
<template>
<div class="flex justify-center items-center h-[30vh] cursor-move">
<div
v-for="(eye, index) in eyes"
:key="index"
class="w-24 h-24 bg-gray-100 dark:bg-gray-500 bg-opacity-50 rounded-full m-5 relative overflow-hidden"
>
<div
class="w-6 h-6 bg-black rounded-full absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
:ref="(el) => (pupils[index] = el)"
></div>
</div>
</div>
</template>
<script setup>
import { animate } from '../public/assets/js/anime.iife.min.js';
import { onMounted, onUnmounted, ref } from 'vue';
const eyes = ref([1, 2]);
const pupils = ref([]);
onMounted(() => {
const handleMouseMove = (e) => {
const mouseX = e.clientX;
const mouseY = e.clientY;
pupils.value.forEach((pupil) => {
if (pupil) {
const eye = pupil.parentNode;
const eyeRect = eye.getBoundingClientRect();
const eyeCenterX = eyeRect.left + eyeRect.width / 2;
const eyeCenterY = eyeRect.top + eyeRect.height / 2;
const dx = mouseX - eyeCenterX;
const dy = mouseY - eyeCenterY;
const angle = Math.atan2(dy, dx);
const maxDistance = eyeRect.width / 2 - pupil.offsetWidth / 2;
const distance = Math.min(maxDistance, Math.sqrt(dx * dx + dy * dy));
const targetX = Math.cos(angle) * distance;
const targetY = Math.sin(angle) * distance;
animate(pupil, {
translateX: targetX,
translateY: targetY,
duration: 300,
easing: 'easeInOutQuad',
update: (anim) => {
pupil.style.transform = `translate(${targetX}px, ${targetY}px)`;
},
});
}
});
};
window.addEventListener('mousemove', handleMouseMove);
});
onUnmounted(() => {
if (handleMouseMove) {
window.removeEventListener('mousemove', handleMouseMove);
}
});
</script>