网站首页 > 开源技术 正文
transition、animation是CSS3中制作DOM元素动画的重要属性,但其仅仅只能应对一些常规的需求,针对非DOM元素的属性过渡时就显得无能为力了,所以接下来通过js简单实现其动画原理(说白了也就是通过JavaScript间接操作目标过渡属性值,每隔一段时间更新一次)让动画变得更加灵活可控,而不是对可恶的pm说这效果有啥用、砍掉这类的话,当然还得看需求使用场景
先给个demo: 针对这样的需求怎么实现呢?
纯css显然已无法做到(图片有点失真,在线众筹换mac, 意思到位了就行~)
简单概述下上面的gif,布局采用了d3实现,针对这种需求常规的可视化图形插件(如ECharts、ichartjs等),通过简单的配置可能已无法做到,就算能实现灵活度也必然受到了限制。熟悉d3的同学实现起来也不会太复杂,图中主要是数字的变化以及弧形的颜色渐变的效果应如何实现,以及整体的联动。下面通过js来描述动画原理,使得更易于掌握css过渡transition及动画animation
关于transition和animation属性介绍有很多文章参考一篇CSS3的动画属性
接下来就使用js简单实现一个让div元素的width属性从20px过渡到200px的动画效果
html代码
<div id="motionPath"></div>
css代码
#motionPath { width: 20px; height: 100px; color:#333; background-color: red; }
在实现之前,先简单了解下贝塞尔曲线的原理参考贝塞尔曲线扫盲,了解了原理之后推荐一个实现三次贝塞尔曲线的js库CubicBezier,也是下文中使用的动画函数,等价CSS transition-timing-function、animation-timing-function
首先定义过渡动画的几个参数:
- paused:控制动画暂停标志
- duration:动画过渡时间
- easing:动画过渡曲线,配置常规的动画过渡曲线参考缓动函数
- update:动画更新时的回调函数
var BezierEasing = require('bezier-easing') var tween = { paused: false, duration: 6000, easing: BezierEasing(0, 0, 1, 0.5), update: function (v) { // anim 是下文定义的一个描述动画的对象 anim.target.innerHTML = v } }
定义一个动画开始函数play()
var raf = null function play() { raf = requestAnimationFrame(function (t) { step(t); }) function step(t) { if (!tween.paused) { setInstanceProgress(t); play(); } else { raf = cancelAnimationFrame(raf); } } }
step() 为动画的入口,这里使用requestAnimationFrame关键帧动画函数,当然也可用setTimeout来模拟实现,但更推荐使用requestAnimationFrame,推荐阅读深入理解requestAnimationFrame。在每一个动画关键帧周期内会调用setInstanceProgress() 函数,下面来看下setInstanceProgress() 函数的实现
function setInstanceProgress(engineTime) { var insTime = engineTime; if (insTime > tween.duration) { tween.paused = true; } var currentTime = Math.min(Math.max(insTime, 0), tween.duration); setAnimationsProgress(currentTime); }
setInstanceProgress() 函数对动画时间进行了修正,同时会判断动画是否应该结束,并将修正的时间传给了setAnimationsProgress() 函数,同样再来看看setAnimationsProgress()函数的实现,我们知道动画其实是“位移”关于“时间”的函数:s=f(t)将动画函数与时间关联起来,计算 t 时刻动画属性值 f(t)
接下来再定义一个描述动画的对象 如下各参数的含义:
- target:过渡的目标对象,当前是div元素
- type:过渡的目标属性类型,元素的width归并于css
- property:目标过渡的属性名,也就是元素的宽width
- fromNumber:过渡的属性的起始值20px
- toNumber:过渡属性的结束值200px
var anim = { target: document.getElementById('motionPath'), type: 'css', property: 'width', fromNumber: 20, toNumber: 200 }
setAnimationsProgress() 函数
function setAnimationsProgress(insTime) { var elapsed = insTime / tween.duration; var eased = tween.easing(elapsed); var value = anim.fromNumber + (eased * (anim.toNumber - anim.fromNumber)) setProgressValue[anim.type](anim.target, anim.property, value); tween.update(value); }
setAnimationsProgress() 函数也就是动画的核心,把时间和过渡函数相结合,计算t时刻对应的value值,再把value值设置到过渡的目标对象属性中去,接下来就是setProgressValue的实现,针对DOM元素,设置width属性也就是设置style对应的属性
var setProgressValue = { css: function (t, p, v) { t.style[p] = v + 'px' }, plainkey: function (t, p, v) { t[p] = v } }
最后只需要运行play()函数,一个简单的动画也就实现了,效果如下:
如果说我们要过渡一个对象plain={key: 0}中的key属性值从 0 到 100 是不是修改一下anim参数就可以了,如下:
var plain = {key: 0} var anim = { target: plain, type: 'plainkey', property: 'key', fromNumber: 0, toNumber: 200 } 复制代码
key值的变化我就不给效果图了,总之通过这样简单的配置就解决了css不能实现类似的需求了,文章开头所说的数字变化的效果就完美的给解决了
最后一个问题了,文章开头的扇形的颜色渐变效果又应该如何实现呢,其实也很简单扇形是通过多份小扇形拼接而成的,然后设置相应的颜色,那每个小扇形应该设置什么样色来达到渐变的效果呢?
举例:从颜色#e8cf22 变化到 #48b532,应用上面所讲的过渡动画原理,#e8cf22对应的rgb格式为rgb(232, 207, 34),#48b532对应的rgb格式为rgb(72, 181, 50),那么分别对R、G、B各值按照对应的起始值和对应的终点值进行过渡(R:从232到72,G:从207到181,B:从34到50),过渡过程中再次组合对应的rgb值就是其过渡对应的颜色值,这就是颜色的过渡渐变原理,下面使用animejs这个库来实现,原理是一样的
html代码
<div id="motionPath"></div>
css代码
#motionPath { color: blue; height: 100px; }
js代码
var oDev = document.getElementById('motionPath') anime({ targets: '#motionPath', duration: 6000, backgroundColor: ['rgb(232, 207, 34)', 'rgb(72, 181, 50)'] easing: 'easeInOutQuad', update: function (instance) { oDev.innerHTML = instance.animations[0].currentValue; } });
效果如下:
综上:了解了js如何实现动画之后,接下来看个使用css3 animation的例子,效果图就不粘出来了。 如下示例代码:
// div <div class="animation"></div> // css .animation { width: 100px; height: 100px; background: red; position: relative; animation: myfirst 4s; animation-timing-function: cubic-bezier(0.42,0,0.58,1); } @keyframes myfirst { 0% {background:red; left:0px; top:0px;} 25% {background:yellow; left:200px; top:0px;} 50% {background:blue; left:200px; top:200px;} 75% {background:green; left:0px; top:200px;} 100% {background:red; left:0px; top:0px;} } /* 效果表现为:让一个长宽都是100px的div元素,在不同的时间阶段,结合过渡函数cubic-bezier(0.42,0,0.58,1)来进行颜色和位置的过渡变化, 那么我想问0%、25%、50%、75%、100%指什么呢,过渡函数cubic-bezier(0.42,0,0.58,1)是应用到整个4s的过渡周期还是每个阶段应用一次完整的过渡? 答案:n%指的是所占过渡时间duration的百分数,0%~25%也就是从0s到1s阶段,然后结合时间t关于过渡函数cubic-bezier(0.42,0,0.58,1)来计算相应的位置点值和颜色值 */
最后
上文中的实现过程,读者你如果使用过animejs 这个动画函数库,也view过源代码,你会发现我只是参考其实现讲了一个大概,具体该函数库中一系列优秀的功能感兴趣的同学可以参考学习,非常值得推荐,目前GitHub上star已到达了30k+
在应对pm提出的一些需求中,只要清晰的知道要过渡那个具体属性,需要从某个起始状态变化到某个指定状态,然后以什么样的方式(过渡函数)来进行过渡,再结合过渡时间 duration,相信有这样的思路必然需求也会迎刃而解
猜你喜欢
- 2024-10-02 寿司快卖,创建一个运行在电脑,手机及Pad上的多屏游戏
- 2024-10-02 P8大佬随手搞个炫酷3D地球,大佬的世界我不懂
- 2024-10-02 十分钟打造 3D 物理世界(3d物理游戏)
- 2024-10-02 极客Web前端开发资源大荟萃#020(极客前端进阶训练营百度云)
- 2024-10-02 HTML5特效库 canvas 弹簧网波动动画特效源码
- 2024-06-21 DGIOT开源物联网集成threejs 3D场景
- 2024-06-21 100道Android 面试常用考题
- 2024-06-21 用HTML5实现字体喷发特效源码
- 2024-06-21 女神节 | 程序员如何低调而又不失逼格
- 2024-06-21 Android开发者面试一百题
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)