使用getAnimations()方法控制CSS动画
<style>.pa p { font: normal 18px/24px sans-serif; margin: 12px 0; }
.pa mark { padding: 2px 6px; background: lightblue; }
.tz { margin: 20px auto; width: 760px; height: 400px; border: 1px solid gray; position: relative; }
.pic { position: absolute; left: 20px; top: 20px; animation: rot 4s linear infinite; }
.pic:nth-of-type(1) { left: 100px; top: 10px; }
.pic:nth-of-type(2) { left: 460px; top: 10px; }
.pic:nth-of-type(3) { left: 320px; top: 200px; }
.tMid { text-align: center; }
@keyframes rot {
to { transform: rotate(360deg); }
}
.mum { position: relative; margin: 12px 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thin solid lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>
<div class="pa">
<p>如下效果是纯CSS关键帧动画,请特别注意,未经干预前动画由CSS直接驱动,三朵花的旋转无限循环:</p>
<div class="tz" id="tz0">
<img class="pic" alt="" src="https://638183.freep.cn/638183/t23/btn/12f.png" />
<img class="pic" alt="" src="https://638183.freep.cn/638183/t23/btn/12f.png" />
<img class="pic" alt="" src="https://638183.freep.cn/638183/t23/btn/12f.png" />
</div>
<p class="tMid">
<button id="onebyone" type="button" value="1">接力旋转</button>
<button id="restore" type="button" value="2" disabled>恢复原状</button>
</p>
<p>点击接力旋转按钮,其中一朵花朵继续旋转,另外两朵花暂停,旋转着的花朵停下,下一朵花紧接着旋转,如此循环往复。点击恢复原状按钮,结束接力赛旋转,三朵花的旋转状态恢复到初始时的样子。</p>
<p>接力运行动画的实现得益于 getAnimations() 方法,该方法由 Web Animations API(简称WAAPI) 提供,我们之前介绍的原生 JS animate() 方法也是由 WAAPI 提供。</p>
<p>getAnimations() 方法可以基于 document 即 DOM,<mark>document.getAnimations();</mark>,这将拿到整个页面的所有动画,包含三种类型的动画:① CSS动画(CSS Animations),② CSS过度动画(CSS Transitions),③ Web动画(Web Animations,即之前介绍的原生JS Animate动画),数据以数组形式存储;也可以基于 element 即某个或某些特定的HTML元素,拿到的也是数组数据。利用这些数据,我们可以相应地管理各类WAAPI所能管理的动画,本文重点讨论的动画类型是CSS动画——如前已述,接力旋转按钮点击后的效果就是通过基于 document 的 getAnimations() 方法实现的。</p>
<p>考虑一下下面的CSS样式表:</p>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">style</span>></cl-cd>
<cl-cd data-idx="2">.pic { <span class="tBlue">position:</span> absolute; <span class="tBlue">left:</span> 20px; <span class="tBlue">top:</span> 20px; <span class="tBlue">animation:</span> rot 4s linear infinite; }</cl-cd>
<cl-cd data-idx="3">@keyframes rot {</cl-cd>
<cl-cd data-idx="4"> to { <span class="tBlue">transform:</span> rotate(360deg); }</cl-cd>
<cl-cd data-idx="5">}</cl-cd>
<cl-cd data-idx="6"><<span class="tDarkRed">/style</span>></cl-cd>
</div>
<p>留意第2行代码,简写形式的 animation 属性中有一个参数 infinite,它是 animation-iteration-count 的值,指动画运行次数,infinite 是无限循环运行。无限循环运行的动画 onfinish 事件(动画完成事件)永远不会被触发,因此需要动态修改动画运行次数,比如改为运行一次。控制CSS关键帧动画可以通过修改元素级CSS样式来处理,我们会拿到要控制动画的所有元素,在JS中这么处理就可以达到目的:</p>
<div class='mum'><cl-cd data-idx="1">element.style.<span class="tRed">animationIterationCount</span> = 1;</cl-cd></div>
<p>当然,如果CSS样式表中直接在简写属性的 animation 值中去掉 infinite,那一切将很简单,我们只需简单地通过 getAnimations() 方法获取所有的动画然后控制这些动画就好。或者,不在CSS样式表中修改动画运行次数,那能否通过拿到的动画操作句柄,使用 WAAPI 的方式去修改动画运行次数呢?针对CSS动画目前不行,<mark>动画对象.iterations = 1;</mark> 这样的设置目前仅能作用于由 JS 的 animate() 方法生成的动画。</p>
<p>修改动画运行次数为1次之后,接着就可以真奔主题,让CSS关键帧动画接力运行。我们要做的仅仅是封装 <mark>动画对象.onfinish</mark> 事件:让前一个动画运行结束时开启下一个动画的运行,并且令其头尾衔接。以下是完整的实现代码,其运行结果是动画一开始就进入接力状态,且每一朵花都具备接受点击功能,通过点击任意一朵花,动画都会在播放、暂停两种状态间切换:</p>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">style</span>></cl-cd>
<cl-cd data-idx="2">.tz { <span class="tBlue">margin:</span> 20px auto; <span class="tBlue">width:</span> 760px; <span class="tBlue">height:</span> 400px; <span class="tBlue">border:</span> 1px solid gray; <span class="tBlue">position:</span> relative; }</cl-cd>
<cl-cd data-idx="3">.pic { <span class="tBlue">position:</span> absolute; <span class="tBlue">left:</span> 20px; <span class="tBlue">top:</span> 20px; <span class="tBlue">animation:</span> rot 4s linear infinite; }</cl-cd>
<cl-cd data-idx="4">.<span class="tBlue">pic:</span>nth-of-type(1) { <span class="tBlue">left:</span> 120px; <span class="tBlue">top:</span> 30px; }</cl-cd>
<cl-cd data-idx="5">.<span class="tBlue">pic:</span>nth-of-type(2) { <span class="tBlue">left:</span> 460px; <span class="tBlue">top:</span> 10px; }</cl-cd>
<cl-cd data-idx="6">.<span class="tBlue">pic:</span>nth-of-type(3) { <span class="tBlue">left:</span> 320px; <span class="tBlue">top:</span> 200px; }</cl-cd>
<cl-cd data-idx="7">@keyframes rot {</cl-cd>
<cl-cd data-idx="8"> to { <span class="tBlue">transform:</span> rotate(360deg); }</cl-cd>
<cl-cd data-idx="9">}</cl-cd>
<cl-cd data-idx="10"><<span class="tDarkRed">/style</span>></cl-cd>
<cl-cd data-idx="11"> </cl-cd>
<cl-cd data-idx="12"><<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"tz"</span>></cl-cd>
<cl-cd data-idx="13"> <<span class="tDarkRed">img</span> class=<span class="tMagenta">"pic"</span> alt=<span class="tMagenta">""</span> src=<span class="tMagenta">"https://638183.freep.cn/638183/t23/btn/12f.png"</span> /></cl-cd>
<cl-cd data-idx="14"> <<span class="tDarkRed">img</span> class=<span class="tMagenta">"pic"</span> alt=<span class="tMagenta">""</span> src=<span class="tMagenta">"https://638183.freep.cn/638183/t23/btn/12f.png"</span> /></cl-cd>
<cl-cd data-idx="15"> <<span class="tDarkRed">img</span> class=<span class="tMagenta">"pic"</span> alt=<span class="tMagenta">""</span> src=<span class="tMagenta">"https://638183.freep.cn/638183/t23/btn/12f.png"</span> /></cl-cd>
<cl-cd data-idx="16"><<span class="tDarkRed">/div</span>></cl-cd>
<cl-cd data-idx="17"> </cl-cd>
<cl-cd data-idx="18"><<span class="tDarkRed">script</span>></cl-cd>
<cl-cd data-idx="19"><span class="tBlue">const</span> pics = <span class="tRed">document</span>.querySelectorAll(<span class="tMagenta">'.pic'</span>); <span class="tGreen">//所有运行动画的元素</span></cl-cd>
<cl-cd data-idx="20"><span class="tBlue">const</span> anis = <span class="tRed">document</span>.getAnimations(); <span class="tGreen">//所有动画对象</span></cl-cd>
<cl-cd data-idx="21"><span class="tBlue">var</span> isplaying = true, current = 0; <span class="tGreen">//播放状态、当前播放的动画索引</span></cl-cd>
<cl-cd data-idx="22"> </cl-cd>
<cl-cd data-idx="23"><span class="tGreen">//遍历动画对象</span></cl-cd>
<cl-cd data-idx="24">anis.forEach((ani,key) => {</cl-cd>
<cl-cd data-idx="25"> pics.style.animationIterationCount = 1; <span class="tGreen">//改变元素的动画运行次数</span></cl-cd>
<cl-cd data-idx="26"> <span class="tBlue">if</span>(key > 0) ani.pause(); <span class="tGreen">//除了第一个动画,都先暂停</span></cl-cd>
<cl-cd data-idx="27"> <span class="tGreen">//如果不是最后一个动画对象,它运行结束时</span></cl-cd>
<cl-cd data-idx="28"> <span class="tBlue">if</span>(key < anis.length - 1) ani.onfinish = () => {</cl-cd>
<cl-cd data-idx="29"> anis.play(); <span class="tGreen">//启动下一个动画</span></cl-cd>
<cl-cd data-idx="30"> current = key + 1; <span class="tGreen">//当前动画索引加 1</span></cl-cd>
<cl-cd data-idx="31"> }</cl-cd>
<cl-cd data-idx="32"> <span class="tGreen">//否则如果是最后一个动画,它运行结束时</span></cl-cd>
<cl-cd data-idx="33"> <span class="tBlue">else</span> ani.onfinish = () => {</cl-cd>
<cl-cd data-idx="34"> anis.play(); <span class="tGreen">//启动第一个动画</span></cl-cd>
<cl-cd data-idx="35"> current = 0; <span class="tGreen">//当前动画索引是 0</span></cl-cd>
<cl-cd data-idx="36"> }</cl-cd>
<cl-cd data-idx="37">});</cl-cd>
<cl-cd data-idx="38"> </cl-cd>
<cl-cd data-idx="39"><span class="tGreen">//花朵点击事件</span></cl-cd>
<cl-cd data-idx="40">pics.forEach((pic, key) => pic.onclick = () => {</cl-cd>
<cl-cd data-idx="41"> <span class="tGreen">//如果动画正在运行,则令当前运行的动画对象暂停,反之,如果动画暂停中,则令当前动画对象播放</span></cl-cd>
<cl-cd data-idx="42"> isplaying ? anis.pause() : anis.play();</cl-cd>
<cl-cd data-idx="43"> isplaying = !isplaying; <span class="tGreen">//布尔变量值取反</span></cl-cd>
<cl-cd data-idx="44">});</cl-cd>
<cl-cd data-idx="45"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
<p>以上代码可以复制到 <a href="http://mhh.52qingyin.cn/api/pcode/" target="_blank">pencil code</a> 或存为本地HTML文档运行以查看运行效果及进行相关研究。</p>
</div>
<script>
var pics = tz0.querySelectorAll('.pic');
var anis = document.getAnimations();
var rot1by1 = (flag) => {
if(flag) {
pics.forEach((pic,key) => {
pic.style.animationIterationCount = 1;
key > 0 ? anis.pause() : anis.play();
var idx = key < pics.length - 1 ? key + 1 : 0;
anis.onfinish = () => anis.play();
});
}else{
pics.forEach((pic,key) => {
pic.style.animationIterationCount = 'infinite';
anis.play();
});
}
};
onebyone.onclick = () => {
rot1by1(true);
restore.disabled = false;
onebyone.disabled = true;
};
restore.onclick = () => {
rot1by1(false);
restore.disabled = true;
onebyone.disabled = false;
}
</script>
综合运用CSS自身属性+JS基于style或attribute属性的操作,也能有效控制CSS关键帧动画,不过操作能力没有借助WAPPI那么强大 每天都有好玩颜值又高的动画效果出炉。。。
老师的教程看得赏心悦目,刚才玩了好大一会儿。。{:4_170:}
接力旋转特别好玩,每个小花转4秒,下一个接上。。
最喜欢这种直观演示的小程序。。。
多种情况可以选择。。。
代码比提供出来的复杂好几倍的样纸。。{:4_199:} 或者,不在CSS样式表中修改动画运行次数,那能否通过拿到的动画操作句柄,使用 WAAPI 的方式去修改动画运行次数呢?针对CSS动画目前不行,动画对象.iterations = 1; 这样的设置目前仅能作用于由 JS 的 animate() 方法生成的动画。
这句最高深了。。{:4_170:} 南无月 发表于 2024-6-13 13:03
或者,不在CSS样式表中修改动画运行次数,那能否通过拿到的动画操作句柄,使用 WAAPI 的方式去修改动画运行 ...
这个的基础在前面的三个讲义里,js原生animate动画 南无月 发表于 2024-6-13 13:02
接力旋转特别好玩,每个小花转4秒,下一个接上。。
最喜欢这种直观演示的小程序。。。
多种情况可以选择 ...
代码自身并不复杂,复杂的是,一没有能领悟JS的诸多内置指令,二没有能理解高于幼儿园大班毕业水平的算法 南无月 发表于 2024-6-13 13:00
每天都有好玩颜值又高的动画效果出炉。。。
老师的教程看得赏心悦目,刚才玩了好大一会儿。。
这个实现起来容易,写成文章有点费脑 去试了,每一朵花儿被点击都能让正在转动的暂停,这个不影响次序的依次轮换{:4_187:} 这个讲解很清楚,黑黑辛苦了{:4_187:} 马黑黑 发表于 2024-6-13 13:05
这个的基础在前面的三个讲义里,js原生animate动画
{:4_181:}好哒,我回去再看看之前教程帮助理解 黑黑的新产品,支持!{:4_187:} 马黑黑 发表于 2024-6-13 13:06
代码自身并不复杂,复杂的是,一没有能领悟JS的诸多内置指令,二没有能理解高于幼儿园大班毕业水平的算法
{:4_170:}老师你说得都对。。都是小白的问题 马黑黑 发表于 2024-6-13 13:07
这个实现起来容易,写成文章有点费脑
老师把知识点都掰开揉碎写出来~还写这么详细的标注。。。老师的教程应是全网最好懂的教程~~{:4_190:}{:4_191:} 南无月 发表于 2024-6-13 17:44
老师把知识点都掰开揉碎写出来~还写这么详细的标注。。。老师的教程应是全网最好懂的教程~~{:4_ ...
那也不一定:有时候我回头看看写过的东东,会看不懂我到底写的啥 南无月 发表于 2024-6-13 17:41
老师你说得都对。。都是小白的问题
{:4_190:} 小辣椒 发表于 2024-6-13 17:41
黑黑的新产品,支持!
没有,这是烟酒烟酒而已 红影 发表于 2024-6-13 14:14
这个讲解很清楚,黑黑辛苦了
手掌辛苦 红影 发表于 2024-6-13 14:14
去试了,每一朵花儿被点击都能让正在转动的暂停,这个不影响次序的依次轮换
{:4_190:} 马黑黑 发表于 2024-6-13 17:46
手掌辛苦
脚掌也辛苦{:4_173:}