JS原生animate动画之:编写自己的动画

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

如下动画效果是我们本文要实现的目标:

100×100的图片在宽高尺寸为740×420的场景下运动,从左上角(0,0)出发,旋转着移动到底部的中央(320,320)并在此处停留,倒转后继续移动到右上角(640,0),然后反方向回到原点接着重复运行。全程图片分两个方向旋转。

我们要设计运动路线及运动形态仅需描述左上角、底部中央、右上角的过程,可以分解为五个步骤,我们用键值对来组织每一步的属性状态描述:

① 从左上角出发 → { left: '0', top: '0' }
② 到达底部中央 → { left: '320px', top: '320px' }
③ 在底部中央旋转 → { transform: 'rotate(720deg)' }
④ 在底部中央逗留 → { left: '320px', top: '320px' }
⑤ 达到右上角 → { left: '640px', top: '0' }

解释一下整个运动过程:

第 ① 步,图片位于左上角(0,0),注意我们用的是CSS属性 left 和 top 来描述,但是,和CSS的表达方式不同:animate(keyframes, options) 的 keyframes 参数要使用键值对的方法来给属性赋值,0 是 0px 的缩写,凡是 0 的值可以不要单位,但它原本是 0px,是字符串,所以 left 键的值 0 要用引号包裹起来,后续各属性值的表达方法也都是同一道理。

第 ② 步,图片的位置移到(320,320)处,让图片处在底部中央,计算方法是:left=(场景宽-图片宽)÷2top=场景高-图片高

前面 ① 和 ② 两步连起来运行,则会:图片从左上角出发,目的地是(320,320)。动画一开始就旋转,但这两步并没有 transform 的 rotate 语句,旋转从哪儿来呢?看下一步:

第 ③ 步位置属性省略,因为它的上一步和下一步位置不改变。这一步旋转 720度,但并不是说到这里才开始旋转,它其实有三层意思:一,整个图片的运动,从出发点到此处,它要旋转 720 度;二,图片在这个地方,也要旋转 720 度;三,图片从这一步开始,要回退旋转720度。具体原因我们稍后会再做详细解释。

第 ④ 步,发生地还在(320,320)处,仅 left 和 top 属性表述,意思是继续停留在{320,320)处。

第 ⑤ 步,达到终点(640,0)。

在第 ③ 步的解释中关于图片的旋转做了简单说明,这里再结合动画的整体效果需要进一步做解释:整个动画过程有 720 度的顺时针旋转设置,这个设置放在第 ③ 步,其余各个环节都省略了 transform: rotate(xxdeg) 设置。省略不意味着没有,默认情况下,第 ① 步是 0deg,从 ① 到 ② 步是 360deg,从 ② 到 ③ 是 720-360=360deg,③ 又独占 720deg,从 ③ 到 ⑤ 则是倒过来从 720deg 到 0deg 的变化,是回退,所以旋转方向是逆时针,其中,③ 到 ④ 分配 360deg,④ 到 5 分配余下的 360deg。为什么会这样?因为,只要存在某一个 transform 设置,其余各个运动节点也都存在,省略时就是元素的初始值,没有初始值时理论上是 0。而 animate() 函数有一个均摊理念,以旋转为例,假设A、B、C三个节点均不设置 rotate 值、D节点设置 360 度,那么,A是开始节点,默认是 0 度,B是 180 度,C是 360 度,就是说,从A到C要完成 360 度的转动,而D独自拥有360度,它要完成 360 度的旋转动作。余下动画节点,假设各个节点也都不设置 rotate 值,那么,最后一个是 0 度,剩下的其余节点要均摊 0-360=-360度 的旋转,回退旋转。

以上,我们描述了动画从左上角到右上角的路线和运动形态,那么,原路返回又是怎么回事、如何实现?这需要用到 animate(keyframes, options) 函数的第二个参数 options,动画属性配置。options 参数以对象的形式组织,放在花括号 {} 里,各键值对间用小角逗号隔开。下面我们给出具体代码,代码中有必要的注释说明:

<style> .artbox p { font: normal 18px/24px sans-serif; } #tz { margin: auto; width: 740px; height: 420px; background: #eee; border: 1px solid gray; position: relative; } #pic { position: absolute; width: 100px; height: 100px; } </style>   <div id="tz">     <img id="pic" src="https://638183.freep.cn/638183/small/4yc.png" alt="" /> </div>     <script> //动画属性配置(对象形式) const opt = {     duration: 10000, //动画周期时长     direction: 'alternate', //动画方向 :双向     iterations: Infinity, //动画重复次数 :永动,Infinity 是JS数字,不用引号 };   //动画关键帧描述(数组形式,数组元素为对象形式) const kfs = [     { left: '0', top: '0' },     { left: '320px', top: '320px' },     { transform: 'rotate(720deg)' },     { left: '320px', top: '320px' },     { left: '640px', top: '0' }, ];   //运行动画并将操作接口赋值给变量 picMove const picMove = pic.animate(kfs, opt);   //鼠标指针滑过图片事件 :动画暂停 pic.onmouseover = () => picMove.pause();   //鼠标指针离开图片事件 :动画继续 pic.onmouseout = () => picMove.play(); </script>

上面的动画描述,数据都是写死了,这会很不方便,比如场景尺寸和图片尺寸若不同于上面的实例,得一一去修改相应数字。我们可以改进一下,将下面的代码替换 ksf 代码块即可,改好后场景、图片的尺寸变化它都能自适应:

const w1 = tz.offsetWidth, //场景宽度     h1 = tz.offsetHeight, //场景高窟     w2 = pic.offsetWidth, //图片宽度     h2 = pic.offsetHeight; //图片高度   const kfs = [     { left: `0`, top: `0` },     { left: `${(w1 - w2) / 2}px`, top: `${h1 - h2}px` },     { transform: `rotate(720deg)` },     { left: `${(w1 - w2) / 2}px`, top: `${h1 - h2}px` },     { left: `${w1 - w2}px`, top: `0` }, ];

声明部分是获取场景和图片的宽高,然后在 kfs 动画数组变量中,在相应描述语句里,比如底部位置、右上角位置等,按前面提到的计算将变量套进去参与计算即可。需要注意的是,新的代码我们使用反引号 ` 代替单引号 ',这样变量和算式可以放在 ${变量和算式} 结构内,与其他字符的拼接是一站式的,正如上面的代码所展示的那样;实际上,即使只是表示纯字符,反引号也可以替代小角单引号、双引号,只要喜欢。

前一篇: 使用getAnimations()方法控制CSS动画
下一篇: JS原生animate动画之:编写自己的动画(续篇)

发表评论:

  
 

评论列表 [3条]

#3 | 小希 于 2024-6-14 22:42 发布: 角落出发可以变左中出发,右中结束。。或者四个运动点。。老师这个教程写得太清楚不过,MS照这个规则可以整出多种运动轨道来~~~

#2 | 悄然 于 2024-6-14 22:40 发布: 这个数据写死的还是非常有必要滴。。。刚试了一下,用带数据的反过来,运动成功。。套用的代码块,还需要略微琢磨一下。。

#1 | 飞飞 于 2024-6-14 17:53 发布: 今天做贴的时候就发现,所有的图片会原路返回,大略看了一遍,这个教程好细致啊。。。晚上细看。。

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