- 原文地址:Integrating Third-Party Animation Libraries to a Project - Part 2
- 原文做者:Travis Almand
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:Baddyo
- 校对者:lgh757079506
在为本文查资料时,我发现第三方动画库中最多见的动画类型就是过渡动画(并不是 CSS transition)了。有些简单的动画应用于元素出入页面的过程。现代单页应用中最司空见惯的模式就是让一个元素进入页面,顶替另外一个离开页面的元素。想一想这种状况:第一个元素淡出而第二个元素淡入。这个动画能够用于新旧数据交替、按顺序移动面板或切换路由到另外一个页面。Sarah Drasner 和 Georgy Marchuk 都列举了不少此类过渡动画的优秀案例。javascript
大多数状况下,动画库不支持在过渡动画中添加或删除元素。用额外的 JavaScript 代码实现的库也许支持这样的功能,但毕竟这样的库不多见,所以咱们如今就来讨论如何实现该功能。css
对于本例,咱们继续使用 Animate.css,并会用到 fadeInDown 动画。html
在 DOM 中插入元素有不少种方式,在此再也不赘述。我仅会展现如何用动画优雅流畅地插入元素,而非让元素生硬地突现。对于 Animate.css(或其余相似的库)来讲,这个功能十分简单。前端
let insertElement = document.createElement('div');
insertElement.innerText = 'this div is inserted';
insertElement.classList.add('animated', 'fadeInDown');
insertElement.addEventListener('animationend', function () {
this.classList.remove('animated', 'fadeInDown');
});
document.body.append(insertElement);
复制代码
你如何建立该元素不重要,关键在于确保元素插入以前添加了所需的类。而后,此元素就会以优雅的动画登场。我还监听了 animationend
事件,用于移除动画类。一般来讲,实现此效果的方式不一而足,而这种方式是最直接的方式了。移除动画类是为了方便实现退场效果。咱们不想让退场动画和进场动画相互冲突。vue
移除单个元素和插入大致相似。目标元素已经存在了,咱们添加所需的动画类就好。而后在 animationend
事件触发时,咱们把该元素从 DOM 中移除。在本例中,咱们会使用 Animate.css 提供的 fadeOutDown
动画,由于它和 fadeInDown
动画是相互呼应的。java
let removeElement = document.querySelector('#removeElement');
removeElement.addEventListener('animationend', function () {
this.remove();
});
removeElement.classList.add('animated', 'fadeOutDown');
复制代码
如你所见,锁定目标元素、添加类以及在动画结束时移除元素,一鼓作气。react
这个过程会有一个问题,那就是随着目标元素的插入或移除,其余元素将会在页面中重排。咱们须要去考虑使用 CSS 技术和一些布局方式去规避这个问题。android
如今咱们要切换两个元素,一进一出。条条大路通罗马,但我举的例子是上文中两个例子的结合。ios
参见 CodePen 上来自 Travis Almand(@talmand)的代码示例:第三方动画库:双元素过渡。git
我会把 JavaScript 代码分块来说解其原理。首先,咱们建立 button、container 变量分别存储对应的两个 DOM 节点。而后,咱们建立 box一、box2 来存储在 container 中要交换的两个元素。
let button = document.querySelector('button');
let container = document.querySelector('.container');
let box1 = document.createElement('div');
let box2 = document.createElement('div');
复制代码
我写了一个通用函数,用来在每次触发 animationEnd
时移除动画类。
let removeClasses = function () {
box1.classList.remove('animated', 'fadeOutRight', 'fadeInLeft');
box2.classList.remove('animated', 'fadeOutRight', 'fadeInLeft');
}
复制代码
第二个函数则是切换功能的核心。首先,咱们肯定当前显示的是哪一个元素。借此咱们能够推断出哪一个元素切入,哪一个切出。切出元素用 switchElements
函数监听,预先移除动画类,避免陷入动画循环。而后,等切出元素的动画完成,咱们将其从容器中移除。接下来,给切入元素添加动画类,并将其插入容器,让它以动画登场。
let switchElements = function () {
let currentElement = document.querySelector('.container .box');
let leaveElement = currentElement.classList.contains('box1') ? box1 : box2;
let enterElement = leaveElement === box1 ? box2 : box1;
leaveElement.removeEventListener('animationend', switchElements);
leaveElement.remove();
enterElement.classList.add('animated', 'fadeInLeft');
container.append(enterElement);
}
复制代码
咱们须要给两个盒子作一些通用设置。接着,将第一个盒子插入到容器中。
box1.classList.add('box', 'box1');
box1.addEventListener('animationend', removeClasses);
box2.classList.add('box', 'box2');
box2.addEventListener('animationend', removeClasses);
container.appendChild(box1);
复制代码
最后,给触发切换的按钮添加点击事件监听。这一系列事件的启动顺序取决于你。在本例中,我打算从按钮点击事件开始。我肯定了正在显示的盒子 —— 即将切出的盒子,给它添加对应的类让它以动画切出。而后我监听切出元素的 animationEnd
事件,触发该事件会调用切实操纵切换的函数 —— 上面列出的 switchElements
函数。
button.addEventListener('click', function () {
let currentElement = document.querySelector('.container .box');
if (currentElement.classList.contains('box1')) {
box1.classList.add('animated', 'fadeOutRight');
box1.addEventListener('animationend', switchElements);
} else {
box2.classList.add('animated', 'fadeOutRight');
box2.addEventListener('animationend', switchElements);
}
}
复制代码
这个例子眼下有个问题:其代码是专门为这一状况写死的。固然了,它也很易于扩展,也能适应不一样场景。故此,该例子只是用来理解如何实现这一功能的。还好,一些诸如 MotionUI 这样的动画库支持用 JavaScript 操纵元素的过渡动画。另外,像 VueJS 这类 JavaScript 框架也支持切换元素的过渡动画。
我在另外一个例子中展现了一个更灵活的系统。它由一个容器构成,该容器存放着用 data 属性引用的切入和切出动画。容器中的两个元素按照命令切换位置。这个例子的原理是,经过 JavaScript 控制 data 属性能够轻松改变更画。Demo 中还有两个容器,一个用的是 Animate.css 实现动画;另外一个用的则是 Animista。这个例子代码量较大,我将不在本文中讲解,但这个例子的注释很充足,感兴趣的话能够看看。
参见 CodePen 上来自 Travis Almand(@talmand)的代码示例:第三方动画库:自定义动画示例。
是全部人都想看到这些动画吗?可能有些人会以为这些动画浮夸,没什么必要,而另外一些人会认为这些动画会致使一些问题。就在前不久,WebKit 为了解决 Vestibular Spectrum Disorder 问题,引入了 prefers-reduced-motion
媒体查询功能。Eric Bailey 也针对该媒体查询功能发表了一篇详尽的说明文章,和一篇关于最佳实践的跟进文章。务必看看这些资料。
那么,你选择的动画库支持 prefers-reduced-motion
吗?若是官方文档没说能支持,那你最好假设不支持。就算官方文档语焉不详,你还能够查看动画库的代码来肯定是否支持,这也容易。例如,Animate.css 在 _base.scss
文件中就有关于媒体查询的代码。
@media (print), (prefers-reduced-motion) {
.animated {
animation: unset !important;
transition: none !important;
}
}
复制代码
若是你选择的动画库不支持媒体查询,那么看到这里的代码,你也会知道如何本身动手写一个补丁。若是该库使用一个通用类 —— 好比 Animate.css 的 animated 类 —— 那你以这个通用类为目标就好了。若是没有这样一个通用类,那你能够选某个特定的动画类或者本身写一个来实现。
.scale-up-center {
animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
}
@keyframes scale-up-center {
0% { transform: scale(0.5); }
100% { transform: scale(1); }
}
@media (print), (prefers-reduced-motion) {
.scale-up-center {
animation: unset !important;
transition: none !important;
}
}
复制代码
能够看到,我比照 Animate.css 中的代码改造了 Animista 中的动画类。记住,你得把所选库中每一个动画类都作这样的处理。在 Eric 的文章中,他建议对全部动画都作渐进加强,以此减小代码并提升用户体验。
在不少方面,React、Vue 这些五花八门的框架,让第三方 CSS 动画库比原生 JavaScript 更加易用,由于你不须要手动接驳那些类或者 animationend
事件。你能够用框架提供的现成功能实现所需效果。使用框架的便利之处在于框架还提供多种操纵动画的方式,知足多种项目需求。下面的例子展现的只是冰山一角。
对于 hover 效果,我建议用 CSS(一如上文中的建议)来设置会比较好。若是你确实须要在 Vue 之类的框架中用 JavaScript 实现,将会是这样:
<button @mouseover="over($event, 'tada')" @mouseleave="leave($event, 'tada')">
tada
</button>
复制代码
methods: {
over: function(e, type) {
e.target.classList.add('animated', type);
},
leave: function (e, type) {
e.target.classList.remove('animated', type);
}
}
复制代码
和上面列举的原生 JavaScript 方案没有太多不一样。 一样地,有不少办法实现该效果。
设置吸引用户注意力的动画效果很是容易。咱们只需添加类名便可,仍然用 Vue 为例:
<div :class="{animated: isPulse, pulse: isPulse}">pulse</div>
<div :class="[{animated: isBounce, bounce: isBounce}, 'infinite']">bounce</div>
复制代码
在 pulse 效果中,当布尔变量 isPulse
的值为 true 时,就会给元素添加两个类名。在 bounce 效果中,当布尔变量 isBounce
的值为 true 时,就会给元素添加 animated
类和 bounce
类。infinite
这个类是默认启用的,这样在布尔变量 isBounce
的值变为 false 以前,bounce效果会一直持续。
幸亏,Vue 的过渡组件能够经过自定义过渡类轻松支持第三方动画类。其余库 —— 好比 React —— 也有相似的功能或插件。要在 Vue 中使用动画类,咱们只需在过渡组件中实现便可。
<transition enter-active-class="animated fadeInDown" leave-active-class="animated fadeOutDown" mode="out-in" >
<div v-if="toggle" key="if">if example</div>
<div v-else key="else">else example</div>
</transition>
复制代码
使用 Animate.css 时,咱们仅仅使用必要的类便可。要实现 enter-active
效果,咱们使用 animated
和 fadeInDown
便可。要实现 leave-active
效果,咱们使用 animated
和 fadeOutDown
便可。在过渡过程当中,这些类会在适当的时候插入。Vue 会替咱们控制类的插入和移除。
想要了解关于在 JavaScript 框架中使用第三方动画库的更复杂的例子,请点击下方连接:
参见 CodePen 上来自 Travis Almand(@talmand)的代码示例:KLKdJy。
这只是一次小小的尝试,还有更多第三方 CSS 动画库等你去探索。有详细完备的,有别出心裁的,有特点鲜明的,有口味偏重的,也有直接明了的。还有针对复杂的 JavaScript 动画的库,例如 Greensock 和 Anime.js。甚至还有专门针对字母动画的库。
真心但愿这些库可以激发你的灵感,创造你本身的 CSS 动画。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。