如何判断一个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
随机推荐
- iOS之ProtocolBuffer搭建和示例demo
这次搭建iOS的ProtocolBuffer编译器和把*.proto源文件编译成*.pbobjc.h 和 *.pbobjc.m文件时,碰到不少问题! 搭建pb编译器到时没有什么问题,只是在把*.pro ...
- System进程(pid=4)占用80端口的解决方案
问题 Mail服务器在安装TFS服务(含SQLServer2016)后启动不了网页服务. 排查问题 使用命令查看端口占用情况 netstat -nao | find ":80" n ...
- 转: 解决Github访问超慢问题
转自:http://zengrong.net/post/2092.htm 解决Github访问超慢问题 Github is so slowly. 这段时间访问 github 都非常慢,google了一 ...
- 带你一分钟理解闭包--js面向对象编程
上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...
- 2000条你应知的WPF小姿势 基础篇<63-68 Triggers和WPF类逻辑结构>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,00 ...
- ABP源码分析二十六:核心框架中的一些其他功能
本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...
- WinForm中显示PDF文件
一.VS2013中,菜单-工具-选择工具箱项-COM组件-勾选“Adobe PDF Reader”-确定 二.在工具箱中就可以看到Adobe PDF Reader控件了,拖到窗体上. 拖到窗体上之后, ...
- Memcached和Redis比较
一.存储 Memcached基本只支持简单的key-value存储方式.Redis除key-value之外,还支持list,set,sorted set,hash等数据结构:Redis支持数据的备份, ...
- 02.Web大前端时代之:HTML5+CSS3入门系列~H5结构元素
Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 1.结构元素 可以理解为语义话标记,比如:以前这么写&l ...
- 如何在博客中使用SublimeText风格的代码高亮样式
因为觉得博客园自带的代码高亮样式很单一,不符合作为前端的我的审美习惯,于是下定决心要想办法折腾出一个方法来应用上另外一套代码高亮样式. 虽然探索的过程是很痛苦的,但最后还是成功了,但也不枉付出的那些努 ...