我们现在想通过按钮的click事件反复触发一个元素的css3动画,点击一次,动画效果就跑一次。现在碰到这样一个问题,我通过click事件给目标元素添加一个带有css3动画的class,动画效果第一次有,后续就不再触发css3动画了。click事件中先删除class再添加还是不行,怎么办?(后面附有测试代码线上链接)
测试代码线上链接如下:
线上测试代码
我们现在想通过按钮的click事件反复触发一个元素的css3动画,点击一次,动画效果就跑一次。现在碰到这样一个问题,我通过click事件给目标元素添加一个带有css3动画的class,动画效果第一次有,后续就不再触发css3动画了。click事件中先删除class再添加还是不行,怎么办?(后面附有测试代码线上链接)
测试代码线上链接如下:
线上测试代码
let [testDiv01,testDiv02,testBtn01,testBtn02]=[$('#testDiv01'),$('#testDiv02'),$('#testBtn01'),$('#testBtn02')];
testBtn01.on('click',function () {
testDiv01.removeClass('transi');
setTimeout(function(){
testDiv01.addClass('transi');
},0)
});
testBtn02.on('click',function () {
testDiv02.removeClass('ani');
setTimeout(function(){
testDiv02.addClass('ani');
},0)
});
这是浏览器渲染机制导致的。
页面等待js线程执行完毕,随后执行GUI线程渲染,而removeClass
随后addClass
这样的代码,对于GUI线程来说页面上没有任何改变,自然不会做任何动作。
而设置了setTimeout
之后,执行顺序为 js线程执行完毕 -> GUI线程渲染(此时页面的class已去除)-> 异步线程执行完毕 -> GUI线程渲染(此时页面的class已添加)
在这样的机制下,如果你把removeClass
和addClass
同时放在setTimeout
中,设置时间间隔大于一定时间(w3c标准是25ms
,但实际能分辨的最小时间间隔会更小一点,因浏览器而异),也有同样的效果。
哈哈哈哈哈哈哈
楼上都不够优雅
testBtn01.on('click',function () {
testDiv01.removeClass('transi');
testDiv01.width(); // Apply change
testDiv01.addClass('transi');
});
浏览器优化,会先计算最终样式最后再同步。计算其宽高等当前样式能强制同步样式再继续执行。
你的代码里点击事件触发立马添加移除class是不行的,起码要做延时再移除,可以试试这样
testBtn01.on('click',function () {
testDiv01.addClass('transi');
let t = setTimeout(()=>{
testDiv01.removeClass('transi');
clearTimeout(t);
},500);
});
可以选择给它加个setTimeout()函数,让它过几毫秒,删除这个类,
`testBtn01.on('click',function(){
testDiv01.addClass('transi');
setTimeout(function(){
testDiv01.removeClass('transi');
},500);
});`
27 回答13k 阅读
8 回答3.5k 阅读✓ 已解决
6 回答1.3k 阅读✓ 已解决
5 回答5.3k 阅读✓ 已解决
4 回答1.6k 阅读✓ 已解决
3 回答1.7k 阅读
4 回答2.3k 阅读✓ 已解决
刚过来就看到看到正确答案真是悲伤的故事。
那我就来稍微解释一下为何
setTimeout 0
在这里能够起到效果吧。如果没有
setTimeout 0
,浏览器的执行流程是这样的:先
removeClass
,然后addClass
,然后让浏览器重新渲染完整个元素属性。这样就不会有transition
动画效果了。其实
setTimeout 0
的作用相当于把内部代码放到当前上下文的最后去执行,在这个问题中的作用就相当于是先
removeClass
,然后让浏览器重新渲染完整个元素属性,然后addClass
。如果解释的不对还请dalao谅解并指出问题。