如何判断一个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
随机推荐
- Spark的StandAlone模式原理和安装、Spark-on-YARN的理解
Spark是一个内存迭代式运算框架,通过RDD来描述数据从哪里来,数据用那个算子计算,计算完的数据保存到哪里,RDD之间的依赖关系.他只是一个运算框架,和storm一样只做运算,不做存储. Spark ...
- ubuntu安装ANSYS17.2全过程
本次介绍在Ubuntu kylin1604下安装Ansys 17.2的全部过程. 1 安装文件准备 关于ANSYS的软件安装文件,在网络上可以找到.这里采用SSQ版本的安装文件,如图所示,包含一个名为 ...
- Vue.js——60分钟组件快速入门(上篇)
组件简介 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树: 那么什么是组件呢?组件可以扩展HTML ...
- 前端如何正确选择offer,到底选哪个?
文章背景:来自于一次线上交流,当时回答感觉比较粗糙,做个阶段性的总结,也分享给其它朋友. 当时的题目是,共2个offer,如何选择: 1. 美团外卖前端 2. 京东深圳前端研发(只有通过邮件,还有收到 ...
- 工大助手(C#与python交互)
工大助手(爬虫--C#与python交互) 基本内容 工大助手(桌面版) 实现登陆.查成绩.计算加权平均分等功能 团队人员 13070046 孙宇辰 13070003 张帆 13070004 崔巍 1 ...
- 领域驱动设计实战—基于DDDLite的权限管理OpenAuth.net
在园子里面,搜索一下“权限管理”至少能得到上千条的有效记录.记得刚开始工作的时候,写个通用的权限系统一直是自己的一个梦想.中间因为工作忙(其实就是懒!)等原因,被无限期搁置了.最近想想,自己写东西时, ...
- ASP.NET Web API 过滤器创建、执行过程(一)
ASP.NET Web API 过滤器创建.执行过程(一) 前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就 ...
- Java基础之IO流
很长时间都没有更新了,最近在补充JavaSE的一些细节部分 关于IO流的一些总结 首先要介绍的是File类,File类用于对文件和目录的一些操作 1.创建文件CreateNewFile() 2.对文件 ...
- struts debug 标签
< s:debug> 引起下面的错误 org.apache.jasper.JasperException: Caught an exception while getting the pr ...
- 【.net 深呼吸】EqualityComparer——自定义相等比较
自定义实现两个对象的相等比较,一种方案是重写Object类的Equals方法,很easy,如果相等返回true,不相等就返回false.不过,如果把自定义相等的比较用于泛型集,比如Dictionary ...