浅谈原生JavaScript的动画和特效
一、JavaScript中的动画原理
动画效果的实现总的来说可分为两种,一种是利用纯css实现,该方法在css3成熟后广泛应用;另外一种是通过JavaScript(或者一些封装的库如jQuery的animate方法)间接的操作css样式,每隔几秒执行一次。这里主要讲的是原生js里面的动画:
1、常用的动画方式
- JavaScript动画用的最多的3个方法是setInterval()、setTimeout()以及requestAnimationFrame():
- 延时器setTimeout()和定时器setInterval ()主要是自身会执行动画效果,它们里面有回调函数function和时间参数,然后通过设置事件就可以用了;
- requestAnimationFrame(回调函数):它是一个全局函数,接收一个回调函数作为参数,在调用该函数后,它会要求浏览器根据自己的频率进行一次重绘,在即将开始的浏览器重绘时,会调用这个函数,并会给这个函数传入调用回调函数时的时间作为参数。
- 值得一提的是,该方法跟setTimeout()特别类似,它的功效也是一次性的,若想达到动画效果,则必须连续不断的调用该函数,所以它应是setTimeout的性能增强版。
- requestAnimationFrame与
setTimeout的区别
是用户指定的,而requestAnimationFrame
是浏览器刷新频率决定的,一般遵循 W3C 标准,它在浏览器每次刷新页面之前执行。
4.清除动画效果:setTimeout()的清除是clearTimeout(),setInterval()的清除是clearInterval(),requestAnimationFrame()的清除则是使用cancelAnimationFrame()
- <button id="btn">清除</button>
- var id;
<script>- var time = new Date();
- requestAnimationFrame(function step(){
- console.log(new Date() - time);
- time = new Date();
- id = requestAnimationFrame(step);
- });
- btn.onclick = function (){
- cancelAnimationFrame(id )
- }
</script>
2、简单动画的一些坑
- setTimeout和setInterval即使是0毫秒执行也会有延迟效果,请看下面的代码
- console.log("1");
- setTimeout(function(){
- console.log("3")
- },0);
- console.log("2");
- //结果是1 2 3
为什么结果不是1 3 2呢,这其实主要是因为:JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序,所以由于受到JavaScript的单线程关系,像setTimeout、setInterva、来自浏览器内核的其他线程如鼠标点击、Ajax异步请求等都得排队等待JavaScript引擎的处理(当线程中没有执行任何同步代码的前提下才会执行异步代码),因此就算setTimeout和setInterva的时间为0,但它原理任然是不变的,也会将其加入到队列末尾,0秒后执行。
- console.log("1");
- 简单动画的变慢问题
当setTimeout、setInterval甚至是requestAnimationFrame在循环里面要做很长的处理时,就会出现动画时间变慢的结果,使它本该在固定时间内结束而结果却是不尽人意的延迟
- function step() {
- var temp = div.offsetLeft + 2;
- div.style.left = temp + "px";
- window.requestAnimationFrame(step);
- for (var i = 0; i < 50000; i++) {
- console.log("等待我执行完才能执行")
- }
- }
- window.requestAnimationFrame(step);
3、填坑
1.动画变慢的结果其实是采用增量的方式来执行了动画,为了更精确的控制动画,更合适的方法是将动画与时间关联起来
2.动画通常情况下有终止时间,如果是循环动画,我们也可以看做特殊的——当动画达到终止时间之后,重新开始动画。因此,我们可以将动画时间归一(Normalize)表示:
- //duration 是动画执行时间 isLoop是否为循环执行。
- function startAnimation(duration, isLoop){
- var startTime = Date.now();
- requestAnimationFrame(function change(){
- // 动画已经用去的时间占总时间的比值
- var p = (Date.now() - startTime) / duration;
- if(p >= 1.0){
- if(isLoop){ // 如果是循环执行,则开启下一个循环周期。并且把开始时间改成上个周期的结束时间
- startTime += duration;
- p -= 1.0; //动画进度初始化
- }else{
- p = 1.0; //如果不是循环,则把时间进度至为 1.0 表示动画执行结束
- }
- }
- console.log("动画已执行进度", p);
- if(p < 1.0){ //如果小于1.0表示动画还诶有值完毕,继续执行动画。
- requestAnimationFrame(change);
- }
- });
- }
做个小栗子:用时间控制动画周期精确到2s中
二、常见动画效果实现
1、 匀速水平运动
用时间来控制进度 s=S∗p
2、匀加速(减速)运动
- 加速度恒定,速度从0开始随时间增加而均匀增加。
- 匀加速公式:大写S:要移动的总距离 p:归一化的时间进度 s=S∗p*p
- 匀减速运动公式:s=S∗p∗(2−p)
3、水平抛物运动
匀速水平运动和自由落体运动的组合
4、正弦曲线运动
正弦运动:x方向匀速,垂直方向是时间t的正弦函数
5、圆周运动
圆周运动公式:x=R.sin(2∗π∗p),y=R.cos(2∗π∗p)
总结:
js原生的动画效果主要有setInterval()、setTimeout()以及requestAnimationFrame()这三种方法,通过设定时间可以对动画做一些简单的效果,但也会出现一些坑,比如它们在循环里面如果要做很长的处理时,就会出现动画时间变慢的结果,这时我们可以采用增量的方式来执行动画,将动画与时间关联起来;
在运动效果方面,我们可以通过各种运动公式,采用归一化时间来控制进度,从而实现运动效果。
浅谈原生JavaScript的动画和特效的更多相关文章
- 浅谈 原生javaScript&&react 实现全局触摸按钮(附带对addeventlistener的了解)
1.采用原生javaACript 实现全局触摸按钮 首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法. 因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位 ...
- 原生JavaScript中动画与特效的实现原理
现如今,许多页面上均有一些动画效果.适当的动画效果可以在一定程度上提高页面的美观度,具有提示效果的动画可以增强页面的易用性. 实现页面动画的途径一般有两种. 一种是通过操作JavaScript间接操作 ...
- 浅谈原生JavaScript实现remove()和recover()
利用原生JavaScript实现: 1.remove(selectors)删除指定的一个或一组元素. 2.recover(selectors)恢复刚才删除的元素. function remove(se ...
- 浅谈 原生javaScript && react 实现全局触摸按钮(附带对addeventlistener的了解)
1.采用原生javaACript 实现全局触摸按钮 首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法. 因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位 ...
- 浅谈前端JavaScript编程风格
前言 多家公司和组织已经公开了它们的风格规范,详细可參阅jscs.info,以下的内容主要參考了Airbnb的JavaScript风格规范.当然还有google的编程建议等编程风格 本章探讨怎样使用E ...
- 原生javascript 基础动画函数封装(二)
<!DOCTYPE html> <html> <head> <title></title> <style type="tex ...
- 原生javascript 基础动画函数封装(一)
<!DOCTYPE html> <html> <head> <title></title> <style type="tex ...
- 原生javascript 基础动画原理
一.实现原理: 1.开定时器前先清除定时器 2.设置定时器 3.当前元素的位置 + 每一步的长度 4.当元素当前位置超过目标点时,把当前位置==目标点 5.设置元素位置,开始运动 6.判断当前位置如果 ...
- JavaScript中toStirng()与Object.prototype.toString.call()方法浅谈
toStirng()与Object.prototype.toString.call()方法浅谈 一.toString()是一个怎样的方法?它是能将某一个值转化为字符串的方法.然而它是如何将一个值从一种 ...
随机推荐
- JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)
1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...
- POJ 1743 Musical Theme ( 后缀数组 && 最长不重叠相似子串 )
题意 : 给 n 个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等. 分析 : 根据题目对于 “ 相似 ” 串的定义,我们可以将原 ...
- Deque 容器
1.Deque (1)定义 deque容器是C++标准模版库(STL,Standard Template Library)中的部分内容.deque容器类与vector类似,支持随机访问和快速插入删除, ...
- 设计模式学习笔记——Adapter 适配器模式
适配器设计模式的适应场景: 一般情况是上端固定,下端固定,下端功能不满足或跟上端不协调,使用适配器重新包一层(继承适配器接口,以满足上端需求,继承下层类,以调用方法),使下端代码能满足上端需求(欺骗, ...
- 《SQL Server 2012 T-SQL基础》读书笔记 - 4.子查询
Chapter 4 Subqueries 子查询分为:独立子查询(Self-Contained Subqueries)和相关子查询(Correlated Subqueries),独立子查询可以单独拿出 ...
- Linux内核调试方法总结之ddebug
[用途] Linux内核动态调试特性,适用于驱动和内核各子系统调试.动态调试的主要功能就是允许你动态的打开或者关闭内核代码中的各种提示信息.适用于驱动和内核线程功能调试. [使用方法] 依赖于CONF ...
- 查看Oracle数据库中的执行计划
1.set autotrace traceonly命令 2.explain plan for命令 1)explain plan for select * from dual; 2)select * f ...
- qbzt day3 晚上 平衡树的一些思想
pks大佬的blog 二叉查找树 任何一个节点左子树的所有元素都小于这个节点,右子树的所有元素都大于这个节点 查找一个节点:从根节点开始,比他小就向左走,比他大就向右走 平衡树:解决二叉查找树的一些痛 ...
- 局域网IP耗尽
w 大量的vm 大量的实例 动态修改 mac
- MongoDB学习【一】—MongoDB简介和安装
一.MongoDB简介 1.MongoDB是什么 MongoDB是一款强大.灵活.且易于扩展的通用型数据库,MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统. 在高负载的 ...