背景

138.2亿年前,世界上没有时间和空间,或许世界都不存在,在一个似有似无的点上,汇集了所有的物质,它孕育着无限的能量与可能性。

宇宙大爆炸

巨大的内力已无法被抑制,瞬间爆发,它爆炸了!世界上有了时间和空间,随着岁月的变迁,时光的流逝,无数的星系、恒星、卫星、彗星形成。我们生活的地球,只是茫茫宇宙中的一个小小的天体,或许在遥远的宇宙的另一边,会有平行世界的存在,或许在那里,我们可能是医生、老师、公务员。科学家说我们的宇宙正在加速度的膨胀,暗能量在无限吞噬着暗物质,未来的世界将会变得虚无缥缈。

人类起源

宇宙的形成,带来了无限可能性,人类释放着欲望和克制,对宇宙的渴望产生于公元前五世纪,古巴比伦人通过观察天体的位置以及外观变化,来预测人世间的各种事物。在遥远的古罗马,人们也舞弄着灵魂,把不羁的想象赋予肉体。Anim,来源于拉丁语,代表着灵魂与生命,代表着所有与生俱来。似乎世间万物都存在联系,宇宙、自然都存在灵魂。

动画的形成

两万五前年钱的石器时代,石洞中的野兽奔跑分析图,这是人类开始试图捕捉动作最早证据。文艺复兴时期的达芬奇画作上,用两只手臂两条腿来标识上下摆动的动作,在一张画作上做出不同时间的两个动作。 直到1906年,世界上第一部动画片《滑稽脸的幽默相》问世。

所以动画是否就是将多个画面连起来播放呢?

时间是连续的吗?是可以无线分割的吗?我也不太清楚,你看到的流星、人们的动作是连续的吗?或许是吧,毕竟现实生活中还没有像瞬间移动这种事情发生吧。

神经可能不是连续的,生物课学过,神经的传递是一个电信号传递过程,并且是颗粒的(神经信号),那么我们看到的东西在我们脑海里的成像一定不是连续的。

那么我们为什么能看到连续的动作呢?

视觉暂留(Persistence of vision),让我们看到了连续的画面,视神经反应速度大约为1/16秒,每个人不太一样,有些人高一点,一些人低一点。上一次视神经传递的图像将会在大脑中存留,直到下一次神经信号到达。维基百科上说,日常用的日光灯每秒钟大约会熄灭100次,但是你并没有感觉。

一般电影的在帧率在24FPS以上,一般30FPS以上大脑会认为是连贯的,我们玩的游戏一般在30FPS,高帧率是60FPS。

小时候一定看过翻页动画吧,可以看一看翻页动画-地球进化史

前端动画实现

Atwood 定律:Any application that can be written in JavaScript will eventually be written in JavaScript.

前端做动画不是什么新鲜事了,从jQuery时代,到当下,无不是前端动画横行的时代。

我们知道多张不同的图像连在一起就变成了动态的图像。

在前端的世界里,浏览器在视觉暂留时间内,连续不断的逐帧输出图像。每一帧输出一张图像。

提及动画一定会讨论到帧率(FPS, Frame Per Second),代表每秒输出帧数,也就是浏览器每秒展示出多少张静态的图像。

DOM动画中的 CSS3

CSS3 动画是当今盛行的 Web 端制作动画的方式之一,对于移动设备来说覆盖率已经非常广泛,在日常开发中可以使用。CSS3 动画只能通过对 CSS 样式的改变控制 DOM 进行动画

  • CSS3 Animation MDN

  • CSS3 Translate MDN

DOM动画中的 WebAnimation

WebAnimation 还在草案阶段,在Chrome可以尝试使用一下。移动设备还是相当惨烈,iOS 并没有开始支持。

Element Animation MDN

CSS3 和 WebAnimation 都只能作用于DOM,那么,如果我们想让 Canvas 上的对象产生动画,那我们该怎么办呢?

JavaScript

既然我们知道动画的原理,其实就是让用户看到连续的图片,并且每一张图片是有变化的。

对于事物来讲,我们可以通过改变某些数值来修改他的属性,从来改变他的外在展示。比如正方形的边长,颜色的RGB值,台风的位置(世界坐标),在每一帧去改变这些数值,根据这些数值将对象绘依次制到屏幕上,将会产生动画。

通过上面的描述,我们知道,实现一个动画,其实是数值随时间变化,以帧为时间单位。

在很久很久以前,JavaScript 使用 setInterval 进行定时调用函数。所以可以使用setInterval来进行数值的改变。

为了更好的让各位前端小哥哥小姐姐们做动画,出现了requestAnimationFramerequestAnimationFrame 接收一个函数,这个函数将在下一帧渲染之前执行,也就是说,不需要太多次的计算,只要在下一帧渲染之前,我们将需要修改的数值修改掉即可。requestAnimationFrame 的帧率和硬件以及浏览器有关,一般是60FPS(16.66666666ms/帧)。

我们利用 Dom 进行动画的演示~

元素移动

创建一个方块

<div class=“box”></div>
复制代码

设置宽高和背景颜色

.box {width: 100px;height: 100px;background: red;
}
复制代码
const box = document.querySelector('.box') // 获取方块元素
let value = 0 // 设置初始值
// 创建每一帧渲染之前要执行的方法
const add = () => {requestAnimationFrame(add) // 下一帧渲染之前继续执行 add 方法value += 5 // 每帧加数值增加5box.style.transform = `translateX(${value}px)` // 将数值设置给 方块 的 css 属性 transform 属性可以控制元素在水平方向上的位移
}
requestAnimationFrame(add) // 下一帧渲染之前执行 add 方法
复制代码

这样,方块每帧向右移动 5 像素,每秒移动60*5=300像素,不是每秒跳动一下,而是一秒在300像素内均匀移动哦。

补间动画

上一个demo实现了小方块从左到右的移动,但是貌似他会永无止境的移动下去,直到数值溢出,小时候学过flash的朋友都知道补间动画,其实就是让小方块0px到300px平滑移动。其实就是固定的时间点,有固定的位置。

所以我们只需要根据运动的已过时间的百分比去计算数值。

保持之前的 HTML 和 CSS 不变

/***  执行补间动画方法** @param      {Number}    start     开始数值* @param      {Number}    end       结束数值* @param      {Number}    time      补间时间* @param      {Function}  callback  每帧的回调函数*/
function animate(start, end, time, callback) {let startTime = performance.now() // 设置开始的时间戳let differ = end - start // 拿到数值差值// 创建每帧之前要执行的函数function loop() {raf = requestAnimationFrame(loop) // 下一阵调用每帧之前要执行的函数const passTime = performance.now() - startTime // 获取当前时间和开始时间差let per = passTime / time // 计算当前已过百分比if (per >= 1) { // 判读如果已经执行per = 1 // 设置为最后的状态cancelAnimationFrame(raf) // 停掉动画}const pass = differ * per // 通过已过时间百分比*开始结束数值差得出当前的数值callback(pass) // 调用回调函数,把数值传递进去}let raf = requestAnimationFrame(loop) // 下一阵调用每帧之前要执行的函数
}复制代码

我们调用一下补间动画,让数值经过1秒匀速从0变成400。

let box = document.querySelector()
animate(0, 400, 1000, value => {box.style.transform = `translateX(${value}px)` // 将数值设置给 方块 的 css 属性 transform 属性可以控制元素在水平方向上的位移
})
复制代码

一个简单的匀速补间动画就这么被我们做好了。

非匀速动画

那万一,这个动画不是非匀速的,比如抖一抖啊,弹一弹,那该怎么办呢?

当然也是一样,根据已过时间的百分比去计算数值

时间是匀速的,但是数值不是,如果数值变化是有规律的,那么我们就可以使用时间来表示数值,创建一个接收时间比例(当前时间百分比),返回当前位置比例(当前位置百分比)的方法。

我们称这个方法叫做缓动方法。

如果速度从慢到快,我们可以把时间和数值的图像模拟成以下的样子。

公式为 rate = time ^ 2

对应的函数应该是

function  easeIn(time) { // 接收一个当前的时间占总时间的百分比比return time ** 2
}
复制代码

这个实现加速后抖动结束的效果,在Time小于0.6时是一个公式,time大于0.6是另外一个公式。

Time < 0.6 时: Rate = Time / 0.6 ^ 2

Time > 0.6 时: Rate = Math.sin((Time-0.6) * ((3 * Math.PI) / 0.4)) * 0.2 + 1

最终实现的函数是

function shake(time) {if (time < 0.6) {return (time / 0.6) ** 2} else {return Math.sin((time-0.6) * ((3 * Math.PI) / 0.4)) * 0.2 + 1}
}
复制代码

我们改造一下之前的 animate 函数,接收一个 easing 方法。

/***  执行补间动画方法** @param      {Number}    start     开始数值* @param      {Number}    end       结束数值* @param      {Number}    time      补间时间* @param      {Function}  callback  每帧回调* @param      {Function}  easing    缓动方法,默认匀速*/
function animate(start, end, time, callback, easing = t => t) {let startTime = performance.now() // 设置开始的时间戳let differ = end - start // 拿到数值差值// 创建每帧之前要执行的函数function loop() {raf = requestAnimationFrame(loop) // 下一阵调用每帧之前要执行的函数const passTime = performance.now() - startTime // 获取当前时间和开始时间差let per = passTime / time // 计算当前已过百分比if (per >= 1) { // 判读如果已经执行per = 1 // 设置为最后的状态cancelAnimationFrame(raf) // 停掉动画}const pass = differ * easing(per) // 通过已过时间百分比*开始结束数值差得出当前的数值callback(pass)}let raf = requestAnimationFrame(loop) // 下一阵调用每帧之前要执行的函数
}复制代码

测试一下,将我们刚刚创建的 easing 方法传进来

加速运动

let box = document.querySelector('.box')
animate(0, 500, 400, value => {box.style.transform = `translateX(${value}px)` // 将数值设置给 方块 的 css 属性 transform 属性可以控制元素在水平方向上的位移
}, easeIn)
复制代码

加速后抖一抖

let box = document.querySelector('.box')
animate(0, 500, 400, value => {box.style.transform = `translateX(${value}px)` // 将数值设置给 方块 的 css 属性 transform 属性可以控制元素在水平方向上的位移
}, shake)
复制代码

总结

这些只是 JavaScript 动画基础中的基础,理解动画的原理后,再做动画就更得心应手了。

市面上有很多JS动画库,大家可以开箱即用。有一些是针对DOM操作的,也有一些是针对 JavaScript 对象。实现原理你都已经懂了。

上述代码已发布到Github: github.com/fanmingfei/…

我的另外两篇关于动画的文章:

  • 为何 Canvas 内元素动画总是在颤抖?
  • 前端动画/游戏开发 requestAnimationFrame 之 锁帧

大话 JavaScript 动画相关推荐

  1. Javascript动画效果(四)

    Javascript动画效果(四) 前面我们自己写了一个小小的关于js动画的插件,下面我们来使用之前的框架来完成我们想要的动画效果.我们经常在淘宝网中看到,鼠标经过某一图片时,该图片有从上滚出而又从下 ...

  2. javascript动画系列第一篇——模拟拖拽

    前面的话 从本文开始,介绍javascript动画系列.javascript本身是具有原生拖放功能的,但是由于兼容性问题,以及功能实现的方式,用的不是很广泛.javascript动画广泛使用的还是模拟 ...

  3. 使用HTML5画布实现的超棒javascript动画仪表板:gauge.js

    日期:2012-8-8  来源:GBin1.com 在线演示 今天我们分享来自guage.js的超棒动画仪表板实现,这个类库使用html5画布来生成动态的自定义仪表板.不依赖于任何类库也不实用任何的C ...

  4. JavaScript动画知多少?

    今天,小学生以自己浅薄的见地,在前辈大能的基础上写这篇文章,希望给大家打开一扇窥探JavaScript(以下简称JS)动画的窗户. JS如何制造出动画效果? 结合浏览器提供的 setInterval ...

  5. 10个顶级的CSS和Javascript动画框架推荐

    在网站中嵌入动画已成为近年来的一个设计趋势,许多公司都已开始转向并拥抱HTML5.CSS3和JavaScript这个技术"三人组".尽管这些技术还不能制作一些非常复杂的动画(像fl ...

  6. 用 65 行代码实现 JavaScript 动画序列播放

    最近在给学生上课,上周六的第一堂课是关于 JavaScript 动画的内容,其中包括一些简单的动画,比如匀速或者匀加/减速的运动,也包括复杂一些的组合动画.而动画的基本原理,在我之前的文章[1]已经有 ...

  7. 《HTML5+JavaScript动画基础》——2.4 JavaScript对象

    本节书摘来自异步社区<HTML5+JavaScript动画基础>一书中的第2章,第2.4节,作者:[美]Billy Lamberta , Keith Peters著,更多章节内容可以访问云 ...

  8. 顶级的CSS和Javascript动画框架

    CodePen 是一个在线的前端代码编辑和展示网站,能够编写代码并即时预览效果.可以欣赏到世界各地的优秀开发者在网页中实现的各种令人惊奇的效果 1. jQuery Transit 该jQuery插件扩 ...

  9. 顶级的CSS和Javascript动画框架推荐

    CodePen 是一个在线的前端代码编辑和展示网站,能够编写代码并即时预览效果.可以欣赏到世界各地的优秀开发者在网页中实现的各种令人惊奇的效果 9. 3D Synth Pure CSS 3D Synt ...

最新文章

  1. oracle+cast函数+长度,oracle cast() 函数问题
  2. java映射文件是哪一种xml_java解析xml的几种方式哪种最好?
  3. python chunk 方式读取大文件——本质上还是file read自身支持
  4. WPS 去掉自动打开的文档漫游和在线模板
  5. c语言第六章条件型循环结构,C语言课件(第六章 循环结构)
  6. java实现二叉查找树_二叉查找树BST----java实现(示例代码)
  7. 今天讲座的感悟--java
  8. 如何成功度过试用期?
  9. 好的安排小明(南阳19)(DFS)
  10. 团队开发中Git冲突解决
  11. Java基础:Collections集合、Map集合综合案例 —— 斗地主
  12. C语言 二维数组(指针)动态分配和释放(转)
  13. (十)unity4.6学习Ugui中文文档-------參考-UGUI Canvas Components
  14. 三农数据(1996-2020)八:农林牧渔业总产值、增加值构成及增加值率、中间消耗
  15. Spring的加密工具类---DigestUtils
  16. 印刷电路板(PCB)基础
  17. 使用vbs语言利用SecureCRT批量执行交换机命令
  18. 结对作业 ——UI组第八组 冯富禹 齐天浩
  19. CISCO ASR9000 密码恢复
  20. Linux挂载逻辑卷

热门文章

  1. 实现树状结构_钢结构设计 | “生命之树”景观案例赏析
  2. java 数据验证_Java 数据验证
  3. W10系统matlab无法保存对该路径的更改 pathdef_MATLAB的运行与窗口介绍
  4. oracle .bash_profile在哪,oracle 11g 测试用户的 .bash_profile 环境变量,路径设置
  5. java 流 存放在哪_java IO流学习
  6. 多个ai文件合并成pdf_如何将多个文档合并成PDF?
  7. 怎么查看python文件的代码_python实现代码查看列举目录下的文件
  8. 栈的pop和peek_从堆栈中移除项目,而不使用pop、peek、push
  9. 二级VB培训笔记07:通用对话框
  10. Java案例:连接SQL Server数据库,显示学生表记录