JS原生animate动画之:编写自己的动画(续篇)

位置: 首页 > 前端三套件
[发布: 2024.6.15  作者: 马黑  阅读: 86]

《JS原生animate动画之:编写自己的动画》一文,我们介绍了使用数组形式将多个动画节点的描述以对象形式封装起来,变量是一个数组,数组元素是有键值对的对象,每一个对象对应于动画的某个时间节点。先来复习一下它的结构,我们以描述运动对象旋转360度为例:

const kfs = [     { transform: 'rotate(0)' },     { transform: 'rotate(360deg)' } ];

上述代码,变量 kfs 是我们声明的 animate() 动画函数所需的第一个 keyframes 的变量,kfs = [...] 这样的结构表明这是一个数组。数组的内容即数组元素由两个对象组成,每一个对象里,transform 是健名,'rotate(...)' 是键值,表示旋转N度。两个对象描述动画运行中在运行时间线上开始和结束时运动对象旋转的角度。这就是关键帧动画,animate() 执行时会将运动周期应旋转的角度均匀地分摊给整个运动过程上的每一帧,达成丝滑流畅的动画效果。

这是我们业已学会的 keyframes 参数值的表达方式,注意它的结构是数组包裹对象、每一个对象所描述的是动画在时间线上某个节点的运动状态。每一个对象可以拥有多个CSS属性,比如 left、color、filter 等等,共同描述该事件节点上运动对象(即HTML元素)的属性变化,即关键帧动画形态。

下面介绍另一种关键帧的表达形式,对象包裹数组,和前面的数组包裹对象的形式刚好相反。同样以运动对象旋转360度为例,看看它的结构:

const kfs = {     transform: ['rotate(0)', 'rotate(360deg)'], };

就是说,kfs 变量这里是一个JS对象(Object)变量,不再是数组变量了。然后,kfs 对象值中,属性名做健名,再用数组将该属性在动画过程中的变化表达出来。上例,我们希望运动对象旋转 360 度,那么,开始时是 0 度,第一个数组元素 'rotate(0)' 描述的就是这个;第二个数组元素,'rotate(360deg)',描述的是动画周期结束时旋转的总度数。可以看出来,对象包裹数组不是纯粹意义上的对象包裹数组这样的结构,而是对象中的健名在各个节点上的变化值用数组来表示,每一个数组元素表示的是在动画时间线上某一节点的关键帧形态——具体说是该属性(如transform)在这个关键帧上是什么值。

此法的特点是,以对象的形式组织关键帧动画,以元素的属性做对象的键名,属性的值使用数组描述不同时间节点上的变化。从形式上看,它和CSS的表述方式更为接近,熟悉CSS的朋友很容易上手。确实它很方便,比方说,我们希望运动对象在旋转的同时还能变换色相,那么,加个键值对就行:

const kfs = { transform: ['rotate(0)', 'rotate(360deg)'],     filter: ['hue-rotate(0)', 'hue-rotate(360deg)'], };

看到了吧?我们加了一个CSS滤镜 filter,滤镜的值从 'hue-rotate(0)' 变为 'hue-rotate(360deg)' ,色相转换。这样运动形态又加了一个功能,通过滤镜实现颜色的变化。

还可以继续加属性。假设我们希望运动对象除了旋转、变换颜色外,还从左上角移到右下角,那么:

const kfs = {     transform: ['rotate(0)', 'rotate(360deg)'],     filter: ['hue-rotate(0)', 'hue-rotate(360deg)'],     left: ['0', '640px'],     top: ['0', '320px'], };

各个属性的值的总数不一定要对称,可以根据设计在不同属性上使用更多的数组元素来描述更多的细节。举例来说,我们希望运动对象先水平方向移动到水平线中央,然后再折向前往右下角,那么可以这样:

const kfs = {     transform: ['rotate(0)', 'rotate(360deg)'],     filter: ['hue-rotate(0)', 'hue-rotate(360deg)'],     left: ['0', '640px'],     top: ['0', '0', '320px'], };

top 属性我们多加了一个节点,'0',表示动画运行时间线上,top 属性分为三个关键帧,第一、二个关键帧 top 的属性值都是 0,第三个关键帧为 320px。animate() 函数会均摊时间,所以,动画运行到一半时,运动对象的位置在上边缘中央处,符合我们的设计需求。

对等功能的数组包裹对象代码也提供一份,大家可以比较一下,看看哪一种形式更合适自己:

const kfs = [     { transform: 'rotate(0)', left: '0', top: '0' },     { top: '0' },     { transform: 'rotate(360deg)', left: '640px', top: '320px' }, ];

最后给出一个完整的演示实例,代码附后:

完整代码:

<style> #tz { margin: 20px auto; width: 740px; height: 420px; background: #eee; border: 1px solid gray; pointer-events: none; position: relative; } #tz::before { content: ''; position: absolute; left: 20px; top: 20px; width: 100px; height: 100px; background: url('https://638183.freep.cn/638183/small/4yc.png') no-repeat center/cover; pointer-events: auto; cursor: pointer; } </style>   <div id="tz" title="暂停/继续"></div>     <script>   //运动属性配置 const opt = {     duration: 6000, //周期时长     iterations: Infinity, // 运行次数     direction: 'alternate', //双向运行动画     pseudoElement: '::before', //指定伪元素 ::before 为运动对象 };   //运动关键帧描述 :对象形式,各属性键使用数组表达关键帧属性值 const kfs = {     transform: ['rotate(0)', 'rotate(720deg)'],     filter: ['hue-rotate(0)', 'hue-rotate(360deg)'],     left: ['0', '640px'],     top: ['0', '0', '320px'], };   //调用 element.animate(keyframes, options) 函数并获取操作接口 move const move = tz.animate(kfs, opt);   //控制动画 :暂停与继续 tz.onclick = () => {     if(move.playState === 'running') move.pause();     else move.play(); }; </script>

前一篇: JS原生animate动画之:编写自己的动画
下一篇: 不改变文档结构实时渲染彩虹字

发表评论:

  
 

评论列表 [3条]

#3 | 飞飞 于 2024-6-15 21:43 发布: 等功能的数组包裹对象代码也提供一份~这里没有滤镜代码呀。

#2 | 悄然 于 2024-6-15 21:41 发布: 数组包裹对象,对象包裹数组本教程才提到的两个不同的概念。。

#1 | 悄然 于 2024-6-15 21:38 发布: 看这个教程的时候,对象包裹数组更加清晰一些。。我还是要重新回去复习上一讲,两个教程一起看才更加明确。。

Copyright © 2023 All Right Reserved 马黑PHP文章管理整站系统v1.8
联系我们: gxblk@163.com