GSAP动画插件-Flip Plugin(一)
本篇文章是GSAP系列的一篇文章,关于web动画,目前我已经发布了以下文章:
web动画篇:
GSAP篇:
其中web动画也可能会用到一定的GSAP动画库的知识。
GSAP是一个非常优秀的动画库,但是不知道为什么中文资料非常少,几乎很少有人会提到GSAP,并且它拥有非常宽裕的使用协议,几乎大部分商业用途都可以免费使用,它的英文文档也非常健全,可以说只要是你见过的web动画,都可以使用GSAP进行实现。
今天的主角是GSAP中的Flip Plugin插件,该插件主要用途是使一个DOM能够平滑的从一个状态转变成另一个状态,具体是什么意思呢?看下面的动图就可以明白:
这不是一个视频,就是官方给出的一个使用Flip Plugin插件做的一个案例。
我们尝试去掉Flip Plugin插件所生成的效果,看看会有什么样的展示:
是不是黯然失色,完全没有过渡动画。
其实说白了Flip这个插件就是实现过渡动画,和CSS属性中的transition
有几分相似之处,不过transition
要实现过渡有着许多的限制,比如必须要指定需要过渡的属性值。
1. Flip.getState()
Flip.getState( targets:String | Element | Array, vars:Object ) : Object
捕获需要操作的目标尺寸、倾斜角度、旋转程度、不透明度、目标在视口中的位置这一系列的信息,后面可以接一个vars
对象,表示额外需要捕捉的信息。
作用就是让Flip知道应该操作哪个目标,以及记录它们的信息,在后面自动填充相关的过渡动画。
2. 几个属性
在Flip插件中,有几个非常重要的属性,接下来一一进行讲解。
2.1 scale
通常情况下,是通过设置元素的宽高来实现元素的缩放,如果你想要更好的动画效果或者更好的性能,可以设置scale: true
,它可以通过元素的scale属性来控制元素的大小。
2.2 absolute
在Flex和Grid布局中,如果过渡动画看起来比较生硬,可以设置absolute: true
。
设置前:
设置后:
2.3 nested
类型:Boolean
。
如果需要过渡的元素上有嵌套的子级元素,设置该属性为true
则可以保证嵌套的子级元素的过渡动画也会正常进行显示。
未设置该属性:
设置该属性:
2.4 spin
值类型:Boolean | Number | Function
。
如果该值为true
则在元素的过渡中会额外旋转360°,也可以用数字来表示旋转方向-1
会反向旋转一次,而1
为正向旋转。
当然也可以通过一个函数来控制旋转方向,比如:
Flip.from(state, { spin: (index, target) => { if (target.classList.contains("clockwise")) { return 1; } else if (target.classList.contains("counter-clockwise")) { return -1; } else { return 0; } }});
2.5 zIndex
该属性是用来设置你需要过渡元素的z-index
属性,因为有时候因为各种原因,导致过渡的时候元素没有表现在最顶层,被其它元素遮挡了一部分,这个时候你就可以通过设置该属性来将元素调整到最顶层。在过渡开始时会立即设置z-index
,而过渡结束后z-index
会被复原。
3. 官方示例的完整代码
这是文章开始时的,那个动画的完整代码,因为动画这玩意使用文字描述起来非常的不容易,所以放出完整的代码可能比较直观,重要的地方我都做了注释。
<!DOCTYPE html><html lang="zh"> <head> <meta charset="UTF-8" /> <meta content="width=device-width, initial-scale=1.0" name="viewport" /> <meta content="ie=edge" http-equiv="X-UA-Compatible" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.0/gsap.min.js"></script> <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/Flip.min.js"></script> <title>Flip Plugin</title> <style> * { box-sizing: border-box; }
body { background: black; padding: 0; margin: 0; font-family: "Signika Negative", sans-serif, Arial; font-weight: 300; height: 100vh; overflow: hidden; }
.container { display: flex; height: 100%; width: 100%; justify-content: center; align-items: center; overflow: hidden; }
.container.grid, .container.columns { align-content: stretch; align-items: stretch; flex-wrap: wrap; }
.letter { text-align: center; color: black; font-size: 10vmax; font-weight: 400; display: flex; align-items: center; justify-content: center; padding: 2px 6px; }
.container.grid .letter { flex-basis: 50%; }
.container.columns .letter { flex-basis: 25%; }
.for, .gsap { font-size: 5vmax; color: white; }
.for { padding: 2px 1.6vmax; font-weight: 300; display: none; }
.gsap { padding: 2px 0; font-weight: 600; display: none; }
.container.final .for, .container.final .gsap { display: block; }
.F { background: rgba(0, 188, 212, 0.7); }
.l { background: rgba(40, 150, 255, 0.7); }
.i { background: rgba(153, 80, 220, 0.7); }
.p { background: rgba(90, 108, 225, 0.7); }
.container.plain .letter { background: transparent; color: white; padding: 0; } </style> </head> <body> <div class="container final"> <div class="letter F">F</div> <div class="letter l">l</div> <div class="letter i">i</div> <div class="letter p">p</div> <div class="for">for</div> <div class="gsap">GSAP</div> </div> <script> gsap.registerPlugin(Flip);
let layouts = ["final", "plain", "columns", "grid"], container = document.querySelector(".container"), curLayout = 0; // 现在动画布局
function nextState() { // 获取元素信息 const state = Flip.getState(".letter, .for, .gsap", { props: "color,backgroundColor", simple: true, });
container.classList.remove(layouts[curLayout]); // 移除旧的类名 curLayout = (curLayout + 1) % layouts.length; // 增量,如果在末尾,则回到起点,即实现动画循环 container.classList.add(layouts[curLayout]); // 增加新的类名,使元素动起来
Flip.from(state, { absolute: true, // 在过渡动画运行的过程中,将元素的position设置为true stagger: 0.07, // 错开属性,让一个元素的动画相对于前一个元素有延迟 duration: 0.7, // 持续时间 ease: "power2.inOut", // 运动轨迹 spin: curLayout === 0, // 控制元素是否旋转 simple: true, // 设置为true时,就不再监听 缩放、旋转、倾斜属性,一般情况下不建议开启,因为性能差别不大 // 对其它元素设置单独动画 onEnter: (elements, animation) => gsap.fromTo( elements, { opacity: 0 }, { opacity: 1, delay: animation.duration() - 0.1 } ), // 对其它元素设置单独动画 onLeave: (elements) => gsap.to(elements, { opacity: 0 }), });
// 为0的时候则表示播放完成 gsap.delayedCall(curLayout === 0 ? 3.5 : 1.5, nextState); } // gsap.delayedCall相当于专门针对动画的setTimeout。 gsap.delayedCall(1, nextState); </script> </body></html>
4. 最后
至于该插件更多的用法可以参考:Flip插件文档。
Flip Plugin插件使用起来并不难,就那么几个api,但是将这几个api正确使用,创造出炫酷的动画就是一个比较困难的事情。
所以HTML中动画的制作是一件非常耗时的过程,同时也非常考验一个开发者对于动画的积累程度,因为大多数关于动画的CSS属性在我们平时编写网页的过程中都不会用到。
所以平时积累HTML动画相关的知识就显得尤为重要,万一哪一天你要开发的某个网页就会用到这些知识呢。