JS变通操作伪元素关键帧动画
JS变通操作伪元素关键帧动画 | 马黑黑由于伪元素在DOM中属于非实体节点,作为擅长操作DOM节点的JS,对伪元素的操作能力极其有限,比如无法直接控制伪元素的关键帧动画。请看下面的CSS和HTML代码:
<style>
#papa {
margin: auto;
width: 700px;
height: 400px;
display: grid;
place-items: center;
position: relative;
}
#papa::before {
position: absolute;
content: '';
width: 100px;
height: 100px;
background: olive;
animation: rot 10s linear infinite;
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="papa"></div>
从CSS中可以看到,id="papa" 的 div 盒子有一个 ::before 伪元素,该伪元素运行了 rot 关键帧动画,不停地自转。现在,我们的任务就是要去控制这个动画,即能够暂停动画和继续动画。
对于非伪元素,JS控制动画的方法是通过 style.animationPlayState 来实现,比如,假设 #papa 盒子运行了 rot 动画,则如下指令无障碍实现暂停和继续动画:
papa.style.animationPlayState = 'paused'; //暂停
papa.style.animationPlayState = 'running'; //继续
遗憾的是,对待 #papa 盒子的伪元素,上述指令无能为力,目前也不存在可以直接操纵伪元素关键帧动画的方法。但问题总要解决,也许可以变通一下思路。
CSS可以拥有变量,比如我们给一系列同用一个类选择器的元素预设不同的宽度,我们可以在CSS中声明一个变量 ww(变量名应该自定义):
.ball {
--ww: 100px;
width: var(--ww);
}
var(--名称) 就是CSS声明变量的方法,var 是声明关键字,小角括号里的 --名称 是固定结构,符号“--”后面紧跟变量名。CSS变量可以有初始值,--名称: 数值+单位,上述代码中的 --ww: 100px; 就是定义了变量 ww 为 100px。
随后,在JS里,可以动态地给元素设定宽度,例如,我们设置 .ball 系列盒子中的第一个的宽度为120px:
let balls = document.querySelectorAll('.ball'); //获得所有 .ball 元素操作句柄
balls.style.setProperty('--ww','120px');
上面,使用JS内置方法 style.setProperty(属性名,值) 改变了CSS变量 --ww 的初始值,令其宽度等于 120px。
CSS变量不止用于尺寸,还可以用于很多其他方面,关键帧动画的状态乃至于动画的名称,也都是可以的。那么,解决问题的思路就来了:我们在 #papa 盒子中声明一个 --state 变量,由于变量的可继承性,父元素的变量会被子元素所接受,我们通过改变父元素的变量值,达成可间接操纵伪元素的动画的目的。
为此,需要改装一下 #papa 盒子的 CSS 样式表:
#papa {
--state: running;
margin: auto;
width: 700px;
height: 400px;
display: grid;
place-items: center;
position: relative;
}
和文章开头提供的代码相比,这里的唯一变化是加入了 --state 变量的初始值为 runnig,表示关键帧动画的 play 状态为运行。
::before 伪元素的CSS样式也配套改动:
#papa::before {
position: absolute;
content: '';
width: 100px;
height: 100px;
background: olive;
animation: rot 10s linear infinite;
animation-play-state: var(--state);
}
仅仅是加了属性 animation-play-state ,其值用变量 var(--state) 表示,var(--state) 将响应来自于父元素的预设值,并将能响应将来JS对此值的动态改变。
为了便于演示,我们需要给HTML代码添加两个按钮,并在JS中处理按钮的点击事件:
<div id="papa">
<p style="position: absolute; bottom: 20px;">
<input id="btnpause" type="button" value=" 暂停 " />
<input id="btnplay" type="button" value=" 继续 " />
</p>
</div>
JS中,使用 style.setProperty() 方法分别处理 #papa 父盒子的预设变量 --state 的值:
<script>
btnpause.onclick = () => {
papa.style.setProperty('--state','paused'); //暂停动画
}
btnplay.onclick = () => {
papa.style.setProperty('--state','running'); //继续动画
}
</script>
效果会怎么样呢?我也没有把握,请移步二楼观看——
<style>
#papa {
--state: running;
margin: auto;
width: 700px;
height: 400px;
display: grid;
place-items: center;
position: relative;
}
#papa::before {
position: absolute;
content: '';
width: 100px;
height: 100px;
background: olive;
animation: rot 10s linear infinite;
animation-play-state: var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="papa">
<p style="position: absolute; bottom: 20px;">
<input id="btnpause" type="button" value=" 暂停 " />
<input id="btnplay" type="button" value=" 继续 " />
</p>
</div>
<script>
btnpause.onclick = () => {
papa.style.setProperty('--state','paused');
}
btnplay.onclick = () => {
papa.style.setProperty('--state','running');
}
</script>
二楼完整代码
<style>
#papa {
--state: running;
margin: auto;
width: 700px;
height: 400px;
display: grid;
place-items: center;
position: relative;
}
#papa::before {
position: absolute;
content: '';
width: 100px;
height: 100px;
background: olive;
animation: rot 10s linear infinite;
animation-play-state: var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="papa">
<p style="position: absolute; bottom: 20px;">
<input id="btnpause" type="button" value=" 暂停 " />
<input id="btnplay" type="button" value=" 继续 " />
</p>
</div>
<script>
btnpause.onclick = () => {
papa.style.setProperty('--state','paused');
}
btnplay.onclick = () => {
papa.style.setProperty('--state','running');
}
</script>
黑黑厉害,思考两三天,到底还是找到了解决JS对伪元素的操作能力的办法,太赞了{:4_199:} 黑黑辛苦了{:4_190:} 感谢老师的代码分享,问好! 马黑黑 发表于 2022-9-26 13:03
#papa {
--state: running;
margin: auto;
这个好,老师辛苦了!{:4_190:} 红影 发表于 2022-9-26 13:50
黑黑厉害,思考两三天,到底还是找到了解决JS对伪元素的操作能力的办法,太赞了
这个是变通方法,原生JS大概只能如此了。 梦缘 发表于 2022-9-26 17:24
这个好,老师辛苦了!
大家都辛苦 梦缘 发表于 2022-9-26 17:24
感谢老师的代码分享,问好!
{:4_190:} 马黑黑 发表于 2022-9-26 18:12
这个是变通方法,原生JS大概只能如此了。
能相出办法来,就很厉害的{:4_187:} 红影 发表于 2022-9-26 19:16
能相出办法来,就很厉害的
这个变通思路 早想到的,只是没时间去鼓捣,今天中午压缩午休时间,匆忙弄出来了 马黑黑 发表于 2022-9-26 19:36
这个变通思路 早想到的,只是没时间去鼓捣,今天中午压缩午休时间,匆忙弄出来了
非常不易,黑黑辛苦了{:4_187:} 红影 发表于 2022-9-26 19:55
非常不易,黑黑辛苦了
想法总是快的,动手总是慢的 马黑黑 发表于 2022-9-26 20:25
想法总是快的,动手总是慢的
这个是个思路实现的过程,很值得留作纪念{:4_187:} 红影 发表于 2022-9-27 20:47
这个是个思路实现的过程,很值得留作纪念
还行,但不必 马黑黑 发表于 2022-9-27 21:12
还行,但不必
嗯嗯,画家不会把自己的画作当回事,其他人会惊艳{:4_173:} 红影 发表于 2022-9-27 22:00
嗯嗯,画家不会把自己的画作当回事,其他人会惊艳
那个我不懂 马黑黑 发表于 2022-9-27 22:35
那个我不懂
自己会作画和自己会写代码一样,自己觉得没什么,其他人会对这些作品非常赞{:4_187:} 红影 发表于 2022-9-28 11:14
自己会作画和自己会写代码一样,自己觉得没什么,其他人会对这些作品非常赞
是吗
页:
[1]