一般情况下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: 1;
-webkit-transform: scale(1);
transform: scale(1); -webkit-transform: scale(1); -moz-transform: scale(1); -o-transform: scale(1);
}
100% {
opacity: 0;
-webkit-transform: scale(1.185);
transform: scale(1.185); -webkit-transform: scale(1.185); -moz-transform: scale(1.185); -o-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也未必具有动画属性,或者该属性被篡改。
文章来自:微信小程序