一般情况下CSS不会直接影响JS的程序逻辑,但是以CSS实现动画的话,这个便不太确定了,这个故事发生在与UED迁移全局样式的过程。

曾经我有一段实现弹出层隐藏动画的代码是这个样子的:

 if (this.needAnimat && typeof this.animateHideAction == 'function' && this.status != 'hide') {
this.animateHideAction.call(this, this.$el);
} else
this.$el.hide();

在所有组件中,如果设置了animatHideAction回调的,便会执行其中的动画逻辑,针对弹出层来说:

① alert

② loading

③ toast

④ 底部弹出层

等组件中动画效果各不相同:

① 动画显示时下沉,隐藏时上浮

② 动画渐隐渐显

③ 组件底部弹出

......

针对通用的动画,一般框架会提供一段CSS类做处理,不满足的情况,各个业务团队便需要自己封装:

 cm-fade-in, .cm-fade-out, .cm-down-in, .cm-down-out, .cm-up-in, .cm-up-out {
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
......
@keyframes fadeOut {
0% {
opacity:;
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
opacity:;
-webkit-transform: scale(1.185);
transform: scale(1.185);
}
}
......

这个时候我们要实现一个居中弹出层渐隐的效果事实上只需要这样做:

 el.addClass('cm-fade-out');

 el.one($.fx.animationEnd, function () {
el.removeClass('cm-fade-out');
el.hide();
});

在动画结束后将对应的动画class移除,再执行真实的hide方法,隐藏dom结构。

其实,我记得是去年的时候我是这么处理这个代码的,当时被一个同事骂了不严谨,今年就使用了animationEnd接口:

 el.addClass('cm-fade-out');

 setTimeout(function () {
el.removeClass('cm-fade-out');
el.hide();
}, 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严谨,但是一定会保证这逻辑代码执行,从某种程度来说,似乎更好,这里的优化代码是:

 var isTrigger = false;

 el.addClass(scope.animateOutClass);

 el.one($.fx.animationEnd, function () {
isTrigger = true;
el.removeClass(scope.animateOutClass);
el.hide();
}); setTimeout(function () {
if (isTrigger) return; el.removeClass(scope.animateOutClass);
el.off($.fx.animationEnd);
el.hide();
}, 350);

如果animationEnd执行了便不理睬setTimeout,否则便走setTimeout逻辑,也不至于影响业务逻辑,但是这个似乎不是最优解决方案。

因为我没有办法,因为这里得有350ms的延迟,在不存在css动画的时候,似乎整个弹出层消失逻辑都变得2B了起来,比较好的方式是,我在执行动画前检测是否具有该css比较靠谱

所以,javascript检测CSS的某一个className是否存在,似乎变成了关键,但是就算就算能找到具有某class,这个class也未必具有动画属性,或者该属性被篡改

况且使用document.styleSheets方式去判断某个样式class是否存在,经过之前的经验,本身就是大坑,还会有跨域什么的场景,坑死人,比如这个代码:

 function getAllSelectors() {
var ret = [];
for (var i = 0; i < document.styleSheets.length; i++) {
var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules;
for (var x in rules) {
if (typeof rules[x].selectorText == 'string') ret.push(rules[x].selectorText);
}
}
return ret;
} function selectorExists(selector) {
var selectors = getAllSelectors();
for (var i = 0; i < selectors.length; i++) {
if (selectors[i] == selector) return true;
}
return false;
} //调用方式
selectorExists('.class');
selectorExists('#id');

上面的代码,本身比较完善了,但是如果某一个css文件跨域的话就完蛋,所以这个方案不靠谱:

① class检测方案本身不靠谱

② 就算class靠谱,也不能保证class就具有动画相关属性,所以也不靠谱!

最终我想到的方案还是对动画属性做检测,检测点主要在动画属性的检测,比如关键属性:

① animation-name

② transition的检测

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script>
<style> .cm-fade-in {
-webkit-animation-name: fadeIn;
animation-name: fadeIn;
} .cm-fade-out {
-webkit-animation-name: fadeOut;
animation-name: fadeOut;
} @-webkit-keyframes fadeIn {
0% {
opacity: 0;
-webkit-transform: scale(0.815);
transform: scale(0.815);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
} @keyframes fadeIn {
0% {
opacity: 0;
-webkit-transform: scale(0.815);
transform: scale(0.815);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
@-webkit-keyframes fadeOut {
0% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
opacity: 0;
-webkit-transform: scale(1.185);
transform: scale(1.185);
}
}
@keyframes fadeOut {
0% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
opacity: 0;
-webkit-transform: scale(1.185);
transform: scale(1.185);
}
}
.cm-down-in {
-webkit-animation-name: downIn;
animation-name: downIn;
} .cm-down-out {
-webkit-animation-name: downOut;
animation-name: downOut;
} @-webkit-keyframes downIn {
0% {
opacity: 0;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
100% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
} @keyframes downIn {
0% {
opacity: 0;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
100% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@-webkit-keyframes downOut {
0% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
100% {
opacity: 0;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
}
@keyframes downOut {
0% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
100% {
opacity: 0;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
}
.cm-up-in {
-webkit-animation-name: upIn;
animation-name: upIn;
} .cm-up-out {
-webkit-animation-name: upOut;
animation-name: upOut;
}
</style>
</head>
<body>
<script type="text/javascript">
var hasAnimationProperty = function (className) {
var animateProprtys = [
//有什么判断的便新增,暂时只判断animation,不同的动画特性,判断方式不一致
// $.fx.cssPrefix + 'transition',
$.fx.cssPrefix + 'animation-name'
];
var el = $('<div></div>');
$('body').append(el); var i, len; //赋予其class
el.attr('class', className); for (i = 0, len = animateProprtys.length; i < len; i++) {
if (el.css(animateProprtys[i]) != 'none') return true;
}
s = '';
return false;
}; //false
console.log(hasAnimationProperty('test'));
//true
console.log(hasAnimationProperty('cm-up-out'));
//true
console.log(hasAnimationProperty('cm-up-in')); </script>
</body>
</html>

核心代码:

 var hasAnimationProperty = function (className) {
var animateProprtys = [
//有什么判断的便新增,暂时只判断animation,不同的动画特性,判断方式不一致
// $.fx.cssPrefix + 'transition',
$.fx.cssPrefix + 'animation-name'
];
var el = $('<div></div>');
$('body').append(el); var i, len; //赋予其class
el.attr('class', className); for (i = 0, len = animateProprtys.length; i < len; i++) {
if (el.css(animateProprtys[i]) != 'none') return true;
}
s = '';
return false;
}; //false
console.log(hasAnimationProperty('test'));
//true
console.log(hasAnimationProperty('cm-up-out'));
//true
console.log(hasAnimationProperty('cm-up-in'));

如此一来,便能判断该class是否具有样式属性了,但是这个代码还需要扩展,而且这么也有性能损害,其中涉及到dom操作了,但是想想动画造成到gpu负担,好像也没什么问题

如何判断一个DOM元素正在动画,一个CSS“阻塞”JS的例子的更多相关文章

  1. 一个DOM元素绑定多个事件时,先执行冒泡还是捕获

    绑定在被点击元素的事件是按照代码顺序发生,其他元素通过冒泡或者捕获“感知”的事件,按照W3C的标准,先发生捕获事件,后发生冒泡事件.所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事 ...

  2. 一个DOM元素同时拥有多个类名时的样式产生冲突时 属性取决于css样式表中后读取到的属性

    如果一个DOM元素包含多个类名,其中的两个类名的属性产生冲突,并不是根据htnl中类名的顺序来决定DOM元素的属性, 而是根据css样式中的顺序来决定DOM元素的属性,它取决于css样式表中后读取到的 ...

  3. JS判断指定dom元素是否在屏幕内的方法实例

    前言 刷网页的时候,有时会遇到这样一个情景,当某个dom元素滚到可见区域时,或者图片的懒加载效果,它就会展现显示动画,十分有趣.那么这是如何实现的呢? 实现原理 想要实现这个功能,就要知道具体的实现原 ...

  4. C++ vector 删除一个指定元素 和 find 一个指定元素以及遍历删除、 map遍历删除元素和删除find到的元素

    vector: 1.delete element 转载:http://www.cnblogs.com/xudong-bupt/p/3522457.html #include <vector> ...

  5. 前端每日实战:35# 视频演示如何把 CSS 径向渐变用得出神入化,只用一个 DOM 元素就能画出国宝熊猫

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/odKrpy 可交互视频教程 此视频 ...

  6. vue中一个dom元素可以绑定多个事件?

    其实这个问题有多个解决方法的  这里提出两点 第一种 第二种 现在dom上绑定一个 然后在你的methods中直接调用 如果要传参数  这时候千万别忘记 原创 如需转载注明出处 谢谢

  7. 原生js获取 一个dom元素距离页面可视区域的位置值 -- getBoundingClientRect

    getBoundingClientRect() 这个方法返回一个矩形对象,包含四个属性:left.top.right和bottom.分别表示元素各边与页面上边和左边的距离. var box=docum ...

  8. 35.在CSS中 只用一个 DOM 元素就能画出国宝熊猫

    原文地址:https://segmentfault.com/a/1190000015052653 感想: 真神奇! HTML code: <div class="panda" ...

  9. CSS中可以通过哪些属性定义,使得一个DOM元素不显示在浏览器可视范围内?

    最基本的: 设置display属性为none,或者设置visibility属性为hidden 技巧性: 设置宽高为0,设置透明度为0,设置z-index位置在-1000

随机推荐

  1. win10电脑优化

    Windows10必做的优化 --道心 关闭服务 右键点击"此电脑",选择"管理",进入"计算机管理"窗口. 在左侧的菜单选择"服 ...

  2. weinre- 调试移动端页面

    相信很多前端的小伙伴一定会遇到一个问题, 比如我编写完一个页面,某个地方需要进行调整细节或者是哪个地方怎么调整都不对,在pc端还好,有google,firefox之类可以调节页面的工具,虽说这些工具有 ...

  3. 我正在使用Xamarin的跨平台框架—Xamarin.Android回忆录

    一.缘起 在自己给别家公司做兼职外包的时候,已经明确知道外包的活不是那么好干的,一般在经历了初期热血澎湃的激情后,逐渐冷淡,愤怒,再冷淡,再愤怒…,听上去好像高潮迭起,但令人尴尬的是,这高潮迭起我们都 ...

  4. MyBatis4:动态SQL

    什么是动态SQL MyBatis的一个强大特性之一通常是它的动态SQL能力.如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的 ...

  5. 系统中没有邮件客户端设置autoLink=email会挂掉的问题

    TextView的autoLink属性为我们提供了很大的便利性,当文本中有网址,邮箱或电话的时候可以让我们方便地执行打电话发邮件等动作,不过也有一些问题,比如说设置autoLink包含email属性, ...

  6. ABP教程-给项目添加SwaggerUI,生成动态webapi

    上一篇,我们是正式将ABP生成的代码项目,跑起来了,然后演示了下多租户的不同.那么这篇我们就来实现下SwaggerUI. Q:SwaggerUI是干什么的呢? A:他是一个能将我们的webapi,通过 ...

  7. 基于Cat的分布式调用追踪

    Cat是美团点评出的一款APM工具,同类的产品也有不少,知名的开源产品如zipkin和pinpoint:国内收费的产品如oneapm.考虑到Cat在互联网公司的应用比较广,因此被纳入选型队列,我也有幸 ...

  8. Atitit.每月数据采集与备份 v4

    Atitit.每月数据采集与备份 v4 备份检查表 r12 00cate 00item im Inputmethod  ok ok Log Log ok cyar Cyar log  ... ok c ...

  9. WCF学习之旅—基于ServiceDebug的异常处理(十七)

    WCF学习之旅—WCF中传统的异常处理(十六) 二.基于ServiceDebug的异常处理 从前面的示例中,可以看到客户端捕获了异常,这是我们处理异常的前提.为了有利于我们进行有效的调试,WCF提供了 ...

  10. Bucket不为空,请检查该Bucket是否包含未删除的Object或者未成功的Multipart碎片

    异常处理汇总 ~ 修正果带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4599258.html 图示解决==>详细如下: