备注:没整理格式,抱歉动画实现的几种方式:性能排序js < requestAnimationFrame <css3< Canvasjs实现方式:1.setTimeout 自身调用 eg12.setInterval 调用 eg2setTimeout的定时器值推荐最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60帧)为什么倒计时动画一定要用setTimeout而避免使用setInterval——-两者区别及setTimeout引发的js线程讨论1.js线程讨论1.1 为什么:单线程是JavaScript的一大特性。JavaScript是浏览器用来与用户进行交互、进行DOM操作的,这也使得了它必须是单线程这一特性。比如你去修改一个元素的DOM,同时又去删除这个元素,那么浏览器应该听谁的?1.2 js单线程工作机制是:当线程中没有执行任何同步代码的前提下才会执行异步代码var t = true;window.setTimeout(function (){ t = false;},1000);while (t){}alert(’end’)JavaScript引擎是单线程运行的,浏览器只有一个线程在运行JavaScript程序1.3 浏览器工作基本原理一、浏览器的内核是多线程的,内核制控下保持同步,至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程(http请求线程等)javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。异步事件:如setTimeOut、浏览器内核的其他线程如鼠标点击、AJAX异步请求等,(当线程中没有执行任何同步代码的前提下才会执行异步代码)也就是说即使setTimeout为0,他也是等js引擎的代码执行完之后才会插入到js引擎线程的最后执行。1.4 JavaScript中任务,一种是同步任务,一种是异步任务。同步任务:各个任务按照文档定义的顺序一一推入"执行栈"中,当前一个任务执行完毕,才会开始执行下一个任务。异步任务:各个任务推入"任务队列"中,只有在当前的所有同步任务执行完毕,才会将队列中的任务"出队"执行。(注:这里的异步任务并不一定是按照文档定义的顺序推入队列中)//只有用户触发点击事件才会被推入队列中(如果点击时间小于定时器指定的时间,则先于定时器推入,否则反之)1.5 “任务队列是什么?异步任务通常包括哪些?“任务队列(event loop):你可理解为用于存放事件的队列,当执行一个异步任务时,就相当于执行任务的回调函数。通常io(ajax获取服务器数据)、用户/浏览器自执行事件(onclick、onload、onkeyup等等)以及定时器(setTimeout、setInterval)都可以算作异步操作。先来看一段代码来理解一下console.log(“1”);setTimeout(function(){console.log(“2”);},1000);console.log(“3”);setTimeout(function(){console.log(“4”);},0);输出结果: 1->3->4->2.那么在来看你这段代码。var t = true;window.setTimeout(function (){t = false},1000);while (t){}alert(’end’);1.6 setTimeOut的讨论参数描述code必需。要调用的函数后要执行的 JavaScript 代码串。millisec必需。在执行代码前需等待的毫秒数。提示:setTimeout() 只执行 code 一次。如果要多次调用,请使用 setInterval() 或者让 code 自身再次原理:setTimeout调用的时候,JavaScript引擎会启动定时器timer,当定时器时间到,就把该事件放到主事件队列等待处理。注意:浏览器JavaScript线程空闲的时候才会真正执行 ep3millisec参数有什么用?那么问题来了。setTimeout(handler,0)和setTimeout(handler,100)在单独使用时,好像并没有区别。(中间执行的代码处理时间超过100ms时)millisec一般在多个setTimeout一起使用的时,需要区分哪个先加入到队列的时候才有用,否则都可以设置成setTimeout(handler,0)1.7 SetTimeout 与 setInterval的区别setTimeout(function(){/* 代码块… */setTimeout(arguments.callee, 10);}, 10);setInterval(function(){/*代码块… */}, 10);setTimeout递归执行的代码必须是上一次执行完了并间格一定时间才再次执行比仿说: setTimeout延迟时间为1秒执行, 要执行的代码需要2秒来执行,那这段代码上一次与下一次的执行时间为3秒. 而不是我们想象的每1秒执行一次.setInterval是排队执行的比仿说: setInterval每次执行时间为1秒,而执行的代码需要2秒执行, 那它还是每次去执行这段代码, 上次还没执行完的代码会排队, 上一次执行完下一次的就立即执行, 这样实际执行的间隔时间为2秒这样的话在我看来, 如果setInterval执行的代码时间长度比每次执行的间隔段的话,就没有意义,并且队伍越来越长,内存就被吃光了.如果某一次执行被卡住了,那程序就会被堵死巨坑无比的setInterval定时器的代码可能在代码还没有执行完成再次被添加到队列,结果导致循环内的判断条件不准确,代码多执行几次,之间没有停顿。JavaScript已经解决这个问题,当使用setInterval()时,仅当没有该定时器的其他代码实例时才将定时器代码插入队列。这样确保了定时器代码加入到队列的最小时间间隔为指定间隔某些间隔会被跳过2.多个定时器的代码执行之间的间隔可能比预期要小大前端团队 > 前端动画实现 > image2017-11-28 14:24:25.png5处,创建一个定时器205处,添加一个定时器,但是onclick代码没执行完成,等待300处,onclick代码执行完毕,执行第一个定时器405处,添加第二个定时器,但前一个定时器没有执行完成,等待605处,本来是要添加第三个定时器,但是此时发现,队列中有了一个定时器,被跳过等到第一个定时器代码执行完毕,马上执行第二个定时器,所以间隔会比预期的小。二 CSS3动画1.tansitiontransition-property 要运动的样式 (all || [attr] || none)transition-duration 运动时间transition-delay 延迟时间transition-timing-function 运动形式ease:(逐渐变慢)默认值linear:(匀速)ease-in:(加速)ease-out:(减速)ease-in-out:(先加速后减速)cubic-bezier 贝塞尔曲线( x1, y1, x2, y2 ) http://matthewlein.com/ceaser/transition的完整写法如下img { transition: 1s 1s height ease;}单独定义成各个属性。img{ transition-property: height; transition-duration: 1s; transition-delay: 1s; transition-timing-function: ease;}/可以多个动画同时运动/用逗号隔开transition:1s width,2s height,3s background;/可以在动画完成时间之后添加动画延迟执行的时间/transition:1s width,2s 1s height,3s 3s background;过渡完成事件// Webkit内核: obj.addEventListener(‘webkitTransitionEnd’,function(){},false);// firefox: obj.addEventListener(’transitionend’,function(){},false);/tansition动画发生在样式改变的时候/function addEnd(obj,fn) —封装适应与各个浏览器的动画结束{ //动画执行完执行该函数 obj.addEventListener(‘WebkitTransitionEnd’,fn,false); obj.addEventListener(’transitionend’,fn,false); //标准}addEnd(oBox,function(){ alert(“end”); });// 面临两个bug:1.tansition中有多个动画时,每个执行完,都会有一个结束弹出 // 2.发生重复调用的情况–需要移除//移除动画执行完的操作function removeEnd(obj,fn)} obj.removeEventListener(’transitionend’,fn,false); obj.removeEventListener(‘WebkitTransitionEnd’,fn,false);{使用注意(1)不是所有的CSS属性都支持transitionhttp://oli.jp/2010/css-animatable-properties/http://leaverou.github.io/animatable/(2)transition需要明确知道,开始状态和结束状态的具体数值,才能计算出中间状态transition的局限transition的优点在于简单易用,但是它有几个很大的局限。(1)transition需要事件触发,所以没法在网页加载时自动发生。(2)transition是一次性的,不能重复发生,除非一再触发。(3)transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。(4)一条transition规则,只能定义一个属性的变化,不能涉及多个属性。CSS Animation就是为了解决这些问题而提出的。2.transformrotate() 旋转函数 取值度数 deg 度数 -origin 旋转的基点skew() 倾斜函数 取值度数skewX()skewY()scale() 缩放函数 取值 正数、负数和小数scaleX()scaleY()translate() 位移函数translateX()translateY()Transform 执行顺序问题 — 后写先执行-webkit-transform:rotate(360deg);旋转原点可以是关键字+像素位置:相对于左上角作为零点:正为下,右-webkit-transform-origin:right bottom;-webkit-transform-origin:200px 200px;一个transform可以有多个值: -webkit-transform:rotate(360deg) scale(0.2);-webkit-transform:skewX(45deg);-webkit-transform:skewY(45deg); -webkit-transform:skew(15deg,30deg);3.Animation 关键帧——keyFrames只需指明两个状态,之间的过程由计算机自动计算关键帧的时间单位数字:0%、25%、100%等字符:from(0%)、to(100%)格式@keyframes 动画名称{动画状态}@keyframes miaov_test{from { background:red; }to { background:green; }}可以只有to必要属性animation-name 动画名称(关键帧名称)animation-duration 动画持续时间属性:animation-play-state 播放状态( running 播放 和paused 暂停 )animation-timing-function 动画运动形式linear 匀速。ease 缓冲。ease-in 由慢到快。ease-out 由快到慢。ease-in-out 由慢到快再到慢。cubic-bezier(number, number, number, number): 特定的贝塞尔曲线类型,4个数值需在[0, 1]区间内animation-delay 动画延迟只是第一次animation-iteration-count 重复次数/infinite为无限次animation-direction 播放前重置/动画是否重置后再开始播放alternate 动画直接从上一次停止的位置开始执行normal 动画第二次直接跳到0%的状态开始执行reversealternate-reverseanimation-fill-modeforwards 让动画保持在结束状态none:默认值,回到动画没开始时的状态。backwards:让动画回到第一帧的状态。both: 根据animation-direction(见后)轮流应用forwards和backwards规则。animation-play-statepausedrunning动画播放过程中,会突然停止。这时,默认行为是跳回到动画的开始状态,想让动画保持突然终止时的状态,就要使用animation-play-state属性大前端团队 > 前端动画实现 > image2017-11-28 14:29:8.pnganimation也是一个简写形式div:hover { animation: 1s 1s rainbow linear 3 forwards normal;}分解成各个单独的属性div:hover { animation-name: rainbow; animation-duration: 1s; animation-timing-function: linear; animation-delay: 1s; animation-fill-mode:forwards; animation-direction: normal; animation-iteration-count: 3;}Animation与Js的结合通过class,在class里加入animation的各种属性直接给元素加-webkit-animation-xxx样式animation的问题写起来麻烦没法动态改变目标点位置animation的函数:obj.addEventListener(‘webkitAnimationEnd’, function (){}, false);实例1:无缝滚动animation的stepeg: http://dabblet.com/gist/1745856animation-timing-function: steps(30, end)1.什么时候使用:animation默认以ease方式过渡,它会在每个关键帧之间插入补间动画,所以动画效果是连贯性的,除了ease,linear、cubic-bezier之类的过渡函数都会为其插入补间。但有些效果不需要补间,只需要关键帧之间的跳跃,这时应该使用steps过渡方式大前端团队 > 前端动画实现 > image2017-11-28 14:29:45.png线性动画: http://sandbox.runjs.cn/show/…帧动画:http://sandbox.runjs.cn/show/…2.step使用:语法:steps(number[, end | start])参数说明:number参数指定了时间函数中的间隔数量(必须是正整数)第二个参数是可选的,可设值:start和end,表示在每个间隔的起点或是终点发生阶跃变化,如果忽略,默认是end。大前端团队 > 前端动画实现 > image2017-11-28 14:30:37.png横轴表示时间,纵轴表示动画完成度(也就是0%~100%)。第一个图,steps(1, start)将动画分为1段,跳跃点为start,也就是说动画在每个周期的起点发生阶跃(即图中的空心圆 → 实心圆)。由于只有一段,后续就不再发生动画了。第二个图,steps(1, end)同样是将动画分为1段,但跳跃点是end,也就是动画在每个周期的终点发生阶跃,也是图中的空心圆 → 实心圆,但注意时间,是在终点才发生动画。第三个图,steps(3, start)将动画分为三段,跳跃点为start,动画在每个周期的起点发生阶跃(即图中的空心圆 → 实心圆)。在这里,由于动画的第一次阶跃是在第一阶段的起点处(0s),所以我们看到的动画的初始状态其实已经是 1/3 的状态,因此我们看到的动画的过程为 1/3 → 2/3 → 1 。第四个图,steps(3, end)也是将动画分为三段,但跳跃点为end,动画在每个周期的终点发生阶跃(即图中的空心圆 → 实心圆)。虽然动画的状态最终会到达100%,但是动画已经结束,所以100%的状态是看不到的,因此我们最终看到的动画的过程是0 → 1/3 → 2/3。https://idiotwu.me/study/timi…steps第一个参数的错误的理解:第一个参数 number 为指定的间隔数,即把动画分为 n 步阶段性展示,估计大多数人理解就是keyframes写的变化次数@-webkit-keyframes circle { 0% {background-position-x: 0;} 100%{background-position-x: -400px;} }@-webkit-keyframes circle { 0% {} 25%{} 50%{} 75%{} 100%{} }如果有多个帧动画@-webkit-keyframes circle { 0% {background-position-x: 0;} 50% {background-position-x: -200px;} 100%{background-position-x: -400px;} } 0-25 之间变化5次, 25-50之间 变化5次 ,50-75 之间变化5次,以此类推应用:Sprite 精灵动画 2D游戏https://idiotwu.me/css3-runni…4.3D转换父容器:transform-style(preserve-3d) 建立3D空间Perspective 景深Perspective- origin 景深基点子元素:Transform 新增函数rotateX()rotateY()rotateZ()translateZ()scaleZ()实例1:3D盒子http://beiyuu.com/css3-animation使用实例:requestAnimationFrame是什么js的一个API该方法通过在系统准备好绘制动画帧时调用该帧,从而为创建动画网页提供了一种更平滑更高效的方法使用var handle = setTimeout(renderLoop, PERIOD);var handle = window.requestAnimationFrame(renderLoop);window.cancelAnimationFrame(handle);为什么出现css:统一的向下兼容策略 IE8, IE9之流CSS3动画不能应用所有属性 scrollTop值。如果我们希望返回顶部是个平滑滚动效果CSS3支持的动画效果有限 CSS3动画的贝塞尔曲线是一个标准3次方曲线缓动(Tween)知识:Linear:无缓动效果Quadratic:二次方的缓动(t^2)Cubic:三次方的缓动(t^3)Quartic:四次方的缓动(t^4)Quintic:五次方的缓动(t^5)Sinusoidal:正弦曲线的缓动(sin(t))Exponential:指数曲线的缓动(2^t)Circular:圆形曲线的缓动(sqrt(1-t^2))Elastic:指数衰减的正弦曲线缓动超过范围的三次方缓动((s+1)t^3 – st^2)指数衰减的反弹缓动js:1.延迟时间固定导致了动画过度绘制,浪费 CPU 周期以及消耗额外的电能等问题2.即使看不到网站,特别是当网站使用背景选项卡中的页面或浏览器已最小化时,动画都会频繁出现大前端团队 > 前端动画实现 > image2017-11-28 14:31:6.png相当一部分的浏览器的显示频率是16.7ms搞个10ms setTimeout,就会是下面一行的模样——每第三个图形都无法绘制显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题requestAnimationFrame 与setTimeout相似,都是延迟执行,不过更智能,跟着浏览器的绘制走,如果浏览设备绘制间隔是16.7ms,那我就这个间隔绘制;如果浏览设备绘制间隔是10ms, 我就10ms绘制,浏览器(如页面)每次要重绘,就会通知(requestAnimationFrame)页面最小化了,或者被Tab切换当前页面不可见。页面不会发生重绘兼容性Android设备不支持,其他设备基本上跟CSS3动画的支持一模一样https://developer.mozilla.org…