如何判断一个DOM元素正在动画,一个CSS“阻塞”JS的例子
一般情况下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的例子的更多相关文章
- 一个DOM元素绑定多个事件时,先执行冒泡还是捕获
绑定在被点击元素的事件是按照代码顺序发生,其他元素通过冒泡或者捕获“感知”的事件,按照W3C的标准,先发生捕获事件,后发生冒泡事件.所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事 ...
- 一个DOM元素同时拥有多个类名时的样式产生冲突时 属性取决于css样式表中后读取到的属性
如果一个DOM元素包含多个类名,其中的两个类名的属性产生冲突,并不是根据htnl中类名的顺序来决定DOM元素的属性, 而是根据css样式中的顺序来决定DOM元素的属性,它取决于css样式表中后读取到的 ...
- JS判断指定dom元素是否在屏幕内的方法实例
前言 刷网页的时候,有时会遇到这样一个情景,当某个dom元素滚到可见区域时,或者图片的懒加载效果,它就会展现显示动画,十分有趣.那么这是如何实现的呢? 实现原理 想要实现这个功能,就要知道具体的实现原 ...
- C++ vector 删除一个指定元素 和 find 一个指定元素以及遍历删除、 map遍历删除元素和删除find到的元素
vector: 1.delete element 转载:http://www.cnblogs.com/xudong-bupt/p/3522457.html #include <vector> ...
- 前端每日实战:35# 视频演示如何把 CSS 径向渐变用得出神入化,只用一个 DOM 元素就能画出国宝熊猫
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/odKrpy 可交互视频教程 此视频 ...
- vue中一个dom元素可以绑定多个事件?
其实这个问题有多个解决方法的 这里提出两点 第一种 第二种 现在dom上绑定一个 然后在你的methods中直接调用 如果要传参数 这时候千万别忘记 原创 如需转载注明出处 谢谢
- 原生js获取 一个dom元素距离页面可视区域的位置值 -- getBoundingClientRect
getBoundingClientRect() 这个方法返回一个矩形对象,包含四个属性:left.top.right和bottom.分别表示元素各边与页面上边和左边的距离. var box=docum ...
- 35.在CSS中 只用一个 DOM 元素就能画出国宝熊猫
原文地址:https://segmentfault.com/a/1190000015052653 感想: 真神奇! HTML code: <div class="panda" ...
- CSS中可以通过哪些属性定义,使得一个DOM元素不显示在浏览器可视范围内?
最基本的: 设置display属性为none,或者设置visibility属性为hidden 技巧性: 设置宽高为0,设置透明度为0,设置z-index位置在-1000
随机推荐
- samba服务
安装samba服务步骤ps -e 查看进程ps -e | grep 文件名 管道符的使用rpm -qa 安装包的查看rpm -qa | grep samba 抓Samba安装包 注释:包与包之间有依赖 ...
- 网站缓存技术总结( ehcache、memcache、redis对比)
网站技术高速发展的今天,缓存技术已经成为大型网站的一个关键技术,缓存设计好坏直接关系的一个网站访问的速度,以及购置服务器的数量,甚至影响到用户的体验. 网站缓存按照存放的地点不同,可以分为客户端缓存. ...
- 二叉树的递归实现(java)
这里演示的二叉树为3层. 递归实现,先构造出一个root节点,先判断左子节点是否为空,为空则构造左子节点,否则进入下一步判断右子节点是否为空,为空则构造右子节点. 利用层数控制迭代次数. 依次递归第二 ...
- CYQ.Data V5 从入门到放弃ORM系列:教程 - AppConfig、AppDebug类的使用
1:AppConfig类的介绍: Public Static (Shared) Properties IsEnumToInt 是否使用表字段枚举转Int方式(默认为false). 设置为true时,可 ...
- 使用Metrics.NET 构建 ASP.NET MVC 应用程序的性能指标
通常我们需要监测ASP.NET MVC 或 Web API 的应用程序的性能时,通常采用的是自定义性能计数器,性能计数器会引发无休止的运维问题(损坏的计数器.权限问题等).这篇文章向你介绍一个新的替代 ...
- 神通广大的CSS3选择器
每个前端工程师可能每天都会写一些css,其中选择器是很主要的一部分.但是,大家可能每天写的大多是#id,.class这样的选择器,这并不稀奇,但是如果我们了解并且熟用css3为我们提供的强大并且优雅的 ...
- 基于Quick-cocos2d-x的资源更新方案 二
写在前面 又是12点半了,对于一个程序员来说,这是一个黄金时间,精力旺盛,我想,是最适合整理和分享一些思路的时候了. 自从上次写了 基于Quick-cocos2d-x的资源更新方案 同样可见quick ...
- Entity Framework 6 Recipes 2nd Edition(11-6)译 -> 从一个”模型定义”函数里返回一个复杂类型
11-6.从一个”模型定义”函数里返回一个复杂类型 问题 想要从一个”模型定义”函数返回一个复杂类型 解决方案 假设我们有一个病人(patient)和他们访客(visit)的模型,如 Figure 1 ...
- Js删除数组重复元素的多种方法
js对数组元素去重有很多种处理的方法,本篇文章中为网络资源整理,当然每个方法我都去实现了:写下来的目的是希望自己活学活用,下次遇到问题后方便解决. 第一种 function oSort(arr){ v ...
- webSocket and LKDBHelper的使用说明
socketket与lkdbhelper来处理数据 客户需求: 当我们有需要从自己的后台推送消息给我们的用户时,用户需要实时的接收到来自我们的推送消息.前提是没有使用第三方的推送框架,那么这个使用we ...