前言
动画效果一直是人机交互的一个非常重要的部分,动画效果的引入,会让交互变得更加友好,让用户获得更加愉悦的体验。而随着市场环境变化,手机性能越来越好,网速越来越快,以及用户视觉效果要求越来越高,作为一名网页开发者,动画也是一个必会的技能。由此本文和大家分享下动画方面的技术实践经验。
动画的形成
多张不同的图像连在一起就会变成了动态的图像。在网页端的世界里,浏览器在视觉暂留时间内,连续不断的逐帧输出图像。每一帧输出一张图像,形成了用户视觉效果中的动画。那么怎么高效的通过一帧帧输出连续流畅的动画,是有很多种动画技术可以都可以实现的。
动画技术
下面以当今主流的动画技术,分成四个部分给大家介绍下,分别为纯Css
、Lottie库
、Svga库
、Creatjs库
。
一、纯CSS
1.1 Animation
动画属性主要结合@keyframes
规则来创建动画。
下面以语音喇叭声波动效为例:
中间的小圆点是一直存在的,第一条和第二条线都是1/4
的圆弧,分别间隔0.2s
去循环显示隐藏。
.second {
animation: fadeInOut 1s infinite 0.2s;
}
.third {
animation: fadeInOut 1s infinite 0.4s;
}
@keyframes fadeInOut {
0% {
opacity: 0;
/*初始状态 透明度为0*/
}
100% {
opacity: 1;
/*结尾状态 透明度为1*/
}
}
我们一般用阶跃函数step
来做帧动画。
下面是linear
和step
的具体案例:
https://codepen.io/huihui/pen/ExPKbdj
先生成Sprite
图片,再移动X
轴位置形成帧动画。
1.2 Transform
属性应用于元素的2D或3D转换。该属性允许我们对元素进行旋转、缩放、倾斜、移动、透视以及使用矩阵函数。分别为rotate
,scale
,skew
,translate
,perspective
以及matrix
。还可以通过transform-origin
用来确定中心点的位置为X、Y、Z
,默认值:50% 50% 0。
这里有个很好的例子来演示Transform
属性:https://c.runoob.com/codedemo/3391
下面以翻牌动效为例,主要是通过透视perspective
属性来实现:
要达到图中第一组翻牌
的效果。首先设置transform-style: preserve-3d
,使被转换的子元素保留其3D
转换。如果不加透视距离perspective
,则会为第三组翻牌
中的效果,扁平没有Z
轴的立体感。其次添加了透视距离后,如果Z
轴相同,三个卡片是会有重叠的现象,如第二组翻牌
中的效果。最后特意给卡片一
加大了Z
轴距离。这样通过透视,如果Z
轴距离越大,卡片就看上去越小。可以用scale
放大了卡片一
。
.card-board{
perspective: 800;
}
.board-item-wrap1{
transform: scale(1.1) translateZ(-100px);
}
提示:一般用
transform: translateZ(0)
,开启3D
引擎,触发GPU
加速,让网页动画更流畅。
1.3 Transition
属性是用来设置动画过渡效果的,可以设置动画的过渡时间和延迟时间。还可以添加动画函数animation-timing-function
,其默认值为ease
。可用贝塞尔曲线来做为动画速度曲线,推荐一个贝塞尔曲线的可视化网址:cubic-bezier,
以地图页的动画为例:
品牌岛屿的移动效果用了ease
,由于后面的品牌需要模糊,设置了较晚模糊的贝塞尔曲线
transition: transform 1s ease,filter 1s cubic-bezier(.06,.45,.82,1.34);
https://cubic-bezier.com/#.06,.45,.82,1.34
1.4 Js
动画事件监听:
动画事件有:
animationstart - CSS动画开始后触发
animationiteration- CSS 动画重复播放时触发
animationend - CSS动画完成后触发
过渡事件有:
transitionend- 该事件在 CSS 完成过渡后触发。
注意:transitionend
存在个问题.如果transition
中,变换的属性有多个,就会触发多次。比如如果同时设置宽高的过渡效果(transition:width:.2s,height:.2s),那么transitionend
事件就会触发2
次。
以2
秒消失提示框为例:
动画结束2
秒后隐藏,用animationEnd
事件来监听。
兼容性:
上面4
个事件都存在兼容性问题,在Android5
下或Ios9.3
下都需要加webkit
前缀才能兼容,例如animationstart
事件在Android5
下需要用webkitAnimationStart
。
兼容性这块本人封装了插件jdyfe-eventployfill,原理是用createElement
创建一个元素但是不插入页面Dom
,查找style
中是否有动画事件,来作为webkit
的兼容判断
使用方法
import { janimationstart, janimationiteration, janimationend, jtransitionend } from'jdyfe-eventPloyfill'
...
dom.addEventListener(janimationstart, ()=>{})
dom.addEventListener(janimationiteration, ()=>{})
dom.addEventListener(janimationend, ()=>{})
dom.addEventListener(jtransitionend, ()=>{})
...
二、Lottie
airbnb
提供的开源动画库Lottie
支持多版本,
React Native
,web
和iOS
,Android
版本
用矢量图导出。
在浏览器中生成的是
svg
标签,不会失真
案例为: https://codepen.io/airnan/pen/MPmQQB
var svgContainer = document.getElementById('svgContainer')
var animItem = bodymovin.loadAnimation({
wrapper: svgContainer,//div的id
animType: 'svg'
loop: true,
path: 'https://labs.nearpod.com/bodymovin/demo/markus/halloween/markus.json'
})
更多Lottie
案例:https://codepen.io/collection/nVYWZR/
Lottie
还和京东的JDReact
框架结合,推出了JDLottieLoadingView
和JDLottieView
组件。其中JDLottieLoadingView
主要是显示加载中的动效,会默认引用loading
动画样式。JDLottieView
是Lottie
在JDReact
上的封装,用法不变。
案例代码如下:
<JDLottieLoadingView
autoSize={false}
source={"loading.json"}
/>
<JDLottieView
autoPlay={true}
autoSize={true}
style=
source={require('./animations/LottieWalkthrough')}
progress={0}
loop={true}
/>
三、Svga
SVGA 是一种跨平台的开源动画格式,集成 svga player 之后可直接使用,安装svgaplayerweb
包即可,
支持多版本,兼容
iOS
/Android
/Flutter
/Web
多个平台的动画格式
支持位图和矢量图
在浏览器中生成的是
canvas
标签
案例代码如下:
import * as SVGA from 'svgaplayerweb'
function AniSvga(props) {
useEffect(() => {
var player = new SVGA.Player('#demoCanvas1')
var parser = new SVGA.Parser('#demoCanvas1') // Must Provide same selector eg:#demoCanvas IF support IE6+
parser.load('./plugin/mengniu.svga', function(videoItem) {
player.setVideoItem(videoItem)
player.startAnimation()
})
return ()=>{
player.clear()
}
}, [])
return (
<div className="jdyfe-svgaPage">
<div id="demoCanvas1" ></div>
</div>
)
}
export default AniSvga
svga
在线预览:https://svga.io/svga-preview.html
某些Android
操作系统缺少Blob
支持,所以需要自行添加Blob Polyfill
。
<script src="//cdn.bootcss.com/blob-polyfill/1.0.20150320/Blob.min.js"></script>
四、Createjs
CreateJS
是基于HTML5
开发的一套模块化的工具库。
基于这些库,可以非常快捷地开发出基于HTML5
的游戏、动画和交互应用。
4.1 EaselJS
EaselJS
提供了JavaScript
库,可轻松操作HTML5 Canvas
元素。
可以绘制Stage舞台、Container容器和Sprite精灵的大小位置等,还提供很多事件可以做交互,很适合纯互动游戏制作。
精灵可以用TexturePacker
软件来生成雪碧图,导出Createjs
的json
文件。
4.2 TweenJs
TweenJs
主要是调整动画属性,例如
target.alpha = 1
createjs.Tween.get(target).wait(500).to({alpha:0, visible:false}, 1000).call(handleComplete)
function handleComplete() {
//渐变完成执行
}
这个渐变将会先等待0.5秒,渐变目标的alpha属性从0到1,并且visible属性从true变为false,这个过程用时1秒,最后调用handleComplete函数。
4.3 SoundJs
SoundJs
主要用来加载处理音频的。
暂停,恢复 声音
控制声音的音量,静音
监听声音实例中的事件,如完成,循环,或失败事件
createjs.Sound.alternateExtensions = ["mp3"]
createjs.Sound.on("fileload", this.loadHandler, this)
createjs.Sound.registerSound("path/to/mySound.ogg", "sound")
function loadHandler(event) {
// 这会引发针对每个已注册的声音。
var instance = createjs.Sound.play("sound") // 发挥使用ID。也可以使用完整的源路径或event.src。
instance.on("complete", this.handleComplete, this)
instance.volume = 0.5
}
4.4 PreloadJS
PreloadJS
是一个用来管理和协调相关资源加载的类库,它可以帮助你预先加载相关资源。对比自己写监听load
事件来确认完成加载,PreloadJS
更方便,并且支持预加载多种类型的数据,例如:图片、文件、音频、数据等等。
PreloadJS
主要是用URL. createObjectURL
创建了Blob
对象,然后赋值给URL,移除的时候用 URL.revokeObjectURL
方法移除Blob
对象。所以会在network
中看到Blob
对象。
import createjs from 'jdyfe-createjs'
const loader = new createjs.LoadQueue(true)
loader.loadManifest([bgAry[0], ...imgAry])
loader.on('complete', function () {
console.log('complete')//全部加载完成
})
loader.on('fileload', function (e) {
console.log('fileload---', e.target.progress)//进度条
})
案例
createjs
官网不支持npm
方式使用,我们用webpack
重新打包生成了一个umd
模块jdyfe-createjs,可供大家下载和使用。
下面案例包含了上面说的4
个模块,也用到了jdyfe-createjs
,具体可看:Belly跑步案例
Happy coding .. :)
相关链接
https://developer.mozilla.org/en-US/docs/Web/API/Animation/play
http://www.createjs.cc/src/docs/tweenjs/classes/CSSPlugin.html