如何判断一个DOM元素正在动画,一个CSS“阻塞”JS的例子

 我来答
若以下回答无法解决问题,邀请你更新回答
育知同创教育
2017-11-07 · 百度知道合伙人官方认证企业
育知同创教育
1【专注:Python+人工智能|Java大数据|HTML5培训】 2【免费提供名师直播课堂、公开课及视频教程】 3【地址:北京市昌平区三旗百汇物美大卖场2层,微信公众号:yuzhitc】
向TA提问
展开全部
一般情况下CSS不会直接影响JS的程序逻辑,但是以CSS实现动画的话,这个便不太确定了,这个故事发生在与UED迁移全局样式的过程。
曾经我有一段实现弹出层隐藏动画的代码是这个样子的:
1 if (this.needAnimat && typeof this.animateHideAction == 'function' && this.status != 'hide') { 2 this.animateHideAction.call(this, this.$el); 3 } else 4 this.$el.hide()
在所有组件中,如果设置了animatHideAction回调的,便会执行其中的动画逻辑,针对弹出层来说:
① alert
② loading
③ toast
④ 底部弹出层
等组件中动画效果各不相同:
① 动画显示时下沉,隐藏时上浮
② 动画渐隐渐显
③ 组件底部弹出
......
针对通用的动画,一般框架会提供一段CSS类做处理,不满足的情况,各个业务团队便需要自己封装:
1 cm-fade-in, .cm-fade-out, .cm-down-in, .cm-down-out, .cm-up-in, .cm-up-out { 2 -webkit-animation-duration: 0.3s; 3 animation-duration: 0.3s; 4 -webkit-animation-fill-mode: both; 5 animation-fill-mode: both; 6 } 7 ...... 8 @keyframes fadeOut { 9 0% { 10 opacity: 1; 11 -webkit-transform: scale(1); 12 transform: scale(1); 13 } 14 100% { 15 opacity: 0; 16 -webkit-transform: scale(1.185); 17 transform: scale(1.185); 18 } 19 } 20 ......
这个时候我们要实现一个居中弹出层渐隐的效果事实上只需要这样做:
1 el.addClass('cm-fade-out'); 2 3 el.one($.fx.animationEnd, function () { 4 el.removeClass('cm-fade-out'); 5 el.hide(); 6 })
在动画结束后将对应的动画class移除,再执行真实的hide方法,隐藏dom结构。
其实,我记得是去年的时候我是这么处理这个代码的,当时被一个同事骂了不严谨,今年就使用了animationEnd接口:
1 el.addClass('cm-fade-out'); 2 3 setTimeout(function () { 4 el.removeClass('cm-fade-out'); 5 el.hide(); 6 }, 340)
这里问题来了,使用animationEnd与setTimeout去除动画class,或者执行业务真实逻辑,到底哪家强,哪个合适?
第一反应都是认为animationEnd比较合理,于是我最近遇到了一个问题:
请求一个数据,loading一直在那里转,永远不消失了!而且执行了hideLoading的操作,与数据延迟毫无关系
于是我开始愉快的定位,当时搞了一会,发现loading的动画没有执行,仔细一定位,发现css中的动画相关的css丢了,于是造成的结果是:
el.addClass('cm-fade-out')
这个代码变成了单纯的class增加,并没有执行动画,也就是,animationEnd的事件没有触发,于是没有执行hide方法,所以loading框就一直在那里转
问题定位到了,解决方案就非常简单了,将css的动画加上即可;但是也说明了,这段代码中JS代码逻辑依赖了CSS相关,从而导致了CSS阻塞JS的假象
这里如果使用setTimeout的话虽然感觉没有animationEnd严谨,但是一定会保证这逻辑代码执行,从某种程度来说,似乎更好,这里的优化代码是:
1 var isTrigger = false; 2 3 el.addClass(scope.animateOutClass); 4 5 el.one($.fx.animationEnd, function () { 6 isTrigger = true; 7 el.removeClass(scope.animateOutClass); 8 el.hide(); 9 }); 10 11 setTimeout(function () { 12 if (isTrigger) return; 13 14 el.removeClass(scope.animateOutClass); 15 el.off($.fx.animationEnd); 16 el.hide(); 17 }, 350)
如果animationEnd执行了便不理睬setTimeout,否则便走setTimeout逻辑,也不至于影响业务逻辑,但是这个似乎不是最优解决方案。
因为我没有办法,因为这里得有350ms的延迟,在不存在css动画的时候,似乎整个弹出层消失逻辑都变得2B了起来,比较好的方式是,我在执行动画前检测是否具有该css比较靠谱
所以,javascript检测CSS的某一个className是否存在,似乎变成了关键,但是就算就算能找到具有某class,这个class也未必具有动画属性,或者该属性被篡改
况且使用document.styleSheets方式去判断某个样式class是否存在,经过之前的经验,本身就是大坑,还会有跨域什么的场景,坑死人,比如这个代码:
1 function getAllSelectors() { 2 var ret = []; 3 for (var i = 0; i < document.styleSheets.length; i++) { 4 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules; 5 for (var x in rules) { 6 if (typeof rules[x].selectorText == 'string') ret.push(rules[x].selectorText); 7 } 8 } 9 return ret; 10 } 11 12 function selectorExists(selector) { 13 var selectors = getAllSelectors(); 14 for (var i = 0; i < selectors.length; i++) { 15 if (selectors[i] == selector) return true; 16 } 17 return false; 18 } 19 20 //调用方式 21 selectorExists('.class'); 22 selectorExists('#id')
上面的代码,本身比较完善了,但是如果某一个css文件跨域的话就完蛋,所以这个方案不靠谱:
① class检测方案本身不靠谱
② 就算class靠谱,也不能保证class就具有动画相关属性,所以也不靠谱!
最终我想到的方案还是对动画属性做检测,检测点主要在动画属性的检测,比如关键属性:
① animation-name
② transition的检测
核心代码:
1 var hasAnimationProperty = function (className) { 2 var animateProprtys = [ 3 //有什么判断的便新增,暂时只判断animation,不同的动画特性,判断方式不一致 4 // $.fx.cssPrefix + 'transition', 5 $.fx.cssPrefix + 'animation-name' 6 ]; 7 var el = $('<div></div>'); 8 $('body').append(el); 9 10 var i, len; 11 12 //赋予其class 13 el.attr('class', className); 14 15 for (i = 0, len = animateProprtys.length; i < len; i++) { 16 if (el.css(animateProprtys[i]) != 'none') return true; 17 } 18 s = ''; 19 return false; 20 }; 21 22 //false 23 console.log(hasAnimationProperty('test')); 24 //true 25 console.log(hasAnimationProperty('cm-up-out')); 26 //true 27 console.log(hasAnimationProperty('cm-up-in'))
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 1条折叠回答
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式