JavaScript中该如何[更好的]做动效
在用js写动画的时候,无非使用 setTimeout/setInterval 或者 requestAnimationFrame 来处理动画(在jquery的代码里也是这么干的),本文主要为了记录下两者的区别及使用两者来实现动过程。
以实现一个简单的滚动到顶部为例
setInterval
setInterval() 方法重复调用一个函数或执行一个代码段,在每次调用之间具有固定的时间延迟。返回一个intervalID,可用于 cancelInterval 达到结束循环的效果。
setTimeout 和 setInterval 的实现基本没区别,一个是定时执行,一个是定时循环执行,前者加个自己调用自己就是后者了,下面主要以 setInterval 为代表
实现过程:
1.写个方法,该方法需要传入一个代表动画所需执行的时间的参数(如:滚动到顶部需要1000毫秒)
function doAnimate(duration){
return function(){
// do something
}
}
2.取当前页面距顶部高度、滚动速度(以匀速为例)、写个开始动画的函数(为了给addEventListener绑事件传参,其实也可直接 dom.onclick = fn )
function doAnimate(duration){
return function(){
var start = document.documentElement.scrollTop;
var scrollSpeed = start/duration*(1000/60); // 以大多浏览器的刷新频率60帧(60Hz)为准 1秒60次的刷新
var timer;
var startTime = +new Date(); // 标记时间,仅供后面测效果用而已
function startAnimate(){
timer = setInterval(function () {
// do something
},1000/60)
}
}
}
3.写滚动动画
function doAnimate(duration){
return function(){
var start = document.documentElement.scrollTop;
var scrollSpeed = start/duration*(1000/60); // 这里取到平均滚动距离,以大多浏览器的刷新频率60帧(60Hz)为准,1秒60次的刷新
var timer;
function startAnimate(){
timer = setInterval(function () {
document.documentElement.scrollTop = start < scrollSpeed ? start -= start : start -= scrollSpeed; // 当前该滚动到何处,如果距离顶部小于平均滚动距离,直接滚到scrollTop为0;如果大于,则取到的触发时高度以平均滚动距离递减
if(start === 0){
clearInterval(timer);
}
},1000/60)
}
}
}
4.写个很高的页面、给个div、加个click事件触发滚动回顶部
html
<!-- 为了更好的看到滚动效果及测滚动是否平滑,我们用某度的大图扔页面上 -->
<img src="./来自百度壁纸的大图" />
<img src="./来自百度壁纸的大图" />
<img src="./来自百度壁纸的大图" /> <div id="scrollTop_1000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:50px;right:50px;text-align: center">1000</div>
<div id="scrollTop_3000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:80px;right:50px;text-align: center">3000</div>
js
function doAnimate(duration){
return function(){
var start = document.documentElement.scrollTop;
var scrollSpeed = start/duration*(1000/60); // 这里取到平均滚动距离,以大多浏览器的刷新频率60帧(60Hz)为准,1秒60次的刷新
var timer;
function startAnimate(){
timer = setInterval(function () {
document.documentElement.scrollTop = start < scrollSpeed ? start -= start : start -= scrollSpeed; // 当前该滚动到何处,如果距离顶部小于平均滚动距离,直接滚到scrollTop为0;如果大于,则取到的触发时高度以平均滚动距离递减
if(start === 0){
clearInterval(timer);
}
},1000/60)
}
}
}
document.getElementById('scrollTop_1000').addEventListener('click',doAnimate(1000),!1)
document.getElementById('scrollTop_3000').addEventListener('click',doAnimate(3000),!1)
效果如图:
截图分别测了设置 duration 为1000和3000的滚动效果
requestAnimationFrame
requestAnimationFrame() 方法告诉浏览器您希望执行动画,并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法将在重绘之前调用的回调作为参数。返回一个 requestID ,可用于 cancelAnimationFrame 达到取消 requestAnimationFrame 动画的效果。
实现思路如上,代码如下:
html
<!-- 为了更好的看到滚动效果及测滚动是否平滑,我们用某度的大图扔页面上 -->
<img src="./来自百度壁纸的大图" />
<img src="./来自百度壁纸的大图" />
<img src="./来自百度壁纸的大图" /> <div id="scrollTop_1000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:50px;right:50px;text-align: center">1000</div>
<div id="scrollTop_3000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:80px;right:50px;text-align: center">3000</div>
js
function doAnimate(duration){
return function(){
var start = document.documentElement.scrollTop;
// 获取实时时间
var nowTime = function(){
return +new Date
}
// 开始时间 用于计算动画运行时间和动画规定时间的百分比
var startTime = nowTime();
var animateId;
var startAnimate = function() {
animateId = requestAnimationFrame(toTop);
}
var stopAnimate = function() {
cancelAnimationFrame(animateId)
}
function toTop(){
// 剩下时间
var restTime = Math.max(0, duration - ( nowTime() - startTime))
var percent = restTime / duration || 0;
var changeStyle = function(value){
document.documentElement.scrollTop = value;
}
// 根本比例获取剩下的距离,也就是实时距离顶部的距离
var distance = start * percent;
if(!distance){
changeStyle(distance)
stopAnimate();
}else{
changeStyle(distance)
startAnimate();
}
}
startAnimate();
}
} document.getElementById('scrollTop_1000').addEventListener('click',doAnimate(1000),!1)
document.getElementById('scrollTop_3000').addEventListener('click',doAnimate(3000),!1)
效果如图:
没区别,没毛病,然而并没有和上面用同一张图...(其实打印下时间,会发现 setInterval 会是1000毫秒以内,大致在960-980毫秒之间,这个梗哪位大神可知???求解!!!)
两者的区别
requestAnimationFrame 会请求浏览器调用指定的函数在下一次重绘之前更新动画,所以开发者不用考虑频率/丢帧问题
setInterval 中,会因为浏览器显示频率和 JavaScript 单线程可能会引发阻塞的问题而导致丢帧(视觉应为动画不流畅)
requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,性能方面更出色
对于隐藏或者不可见的元素,requestAnimationFrame 将不会进行重绘或回流,这点可减少cpu,gpu及内存的负荷
setInterval 兼容一些老版本的浏览器(jquery保留这个应该也是为了兼容老版本浏览器...)
requestAnimationFrame 兼容图
顺便扔上jquery里animate的部分代码:
jQuery.fx.start = function() {
if ( !timerId ) {
timerId = window.requestAnimationFrame ?
window.requestAnimationFrame( raf ) :
window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
}
}; jQuery.fx.stop = function() {
if ( window.cancelAnimationFrame ) {
window.cancelAnimationFrame( timerId );
} else {
window.clearInterval( timerId );
} timerId = null;
};
略显尴尬... 在我windows上和mac上也保留一些老版本的浏览器,测效果的结果简直蛋疼...看来兼容方面还是需要做处理的,天将降大任于 setInterval 啊 :-D
欢迎交流 欢迎指出各个问题~
JavaScript中该如何[更好的]做动效的更多相关文章
- JavaScript中的该如何[更好的]做动效
在用js写动画的时候,无非使用 setTimeout/setInterval 或者 requestAnimationFrame 来处理动画(在jquery的代码里也是这么干的),本文主要为了记录下两者 ...
- Google I/O 官方应用中的动效设计
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jILRvRTrc/article/details/82881743 作者:Nick Butcher, ...
- IOS5中的Safari不兼容Javascript中的Date问题,做下笔录吧!奶奶的,折腾我半天!
在做Mobile终端的Website开发中,我遇到一个很懊恼的问题. 在IOS5以上版本(不包含IOS5)中的Safari浏览器能正确解释出Javascript中的 new Date('2013-10 ...
- Javascript中几个看起来简单,却不一定会做的题
Javascript作为前端开发必须掌握的一门语言,因为语言的灵活性,有些知识点看起来简单,在真正遇到的时候,却不一定会直接做出来,今天我们就一起来看看几道题目吧 题目1 var val = 'smt ...
- javascript中,一个js中的函数,第一句var _this = this;为什么要这样做?
javascript中,一个js中的函数,第一句var _this = this;为什么要这样做? 下面是源码: 下面这段代码是常用的网站首页,自动切换span或者tabbar来变更List显示内容的 ...
- JavaScript 中的数据类型
Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...
- 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型
前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...
- 理解JavaScript中的“this”
对于javascript的初学者来说,一般对“this”关键字都感到非常迷惑.本文的目的旨在让你全面的了解“this”,理解在每一个情景下如何使用“this”,希望通过本文,可以帮助同学们不在害怕“t ...
- 详解Javascript中正则表达式的使用
正则表达式用来处理字符串特别好用,在JavaScript中能用到正则表达式的地方有很多,本文对正则表达式基础知识和Javascript中正则表达式的使用做一个总结. 第一部分简单列举了正则表达式在Ja ...
随机推荐
- 19-background
先来讲讲颜色表示法 一共有三种:单词.rgb表示法.十六进制表示法 rgb:红色 绿色 蓝色 三原色光学显示器,每个像素都是由三原色的发光原件组成的,靠明亮度不同调成不同的颜色的.用逗号隔开,r.g. ...
- bzoj1212(trie+dp)
开始一看多个字符串就想ac自动机,结果发现不行.果然学傻了,,,,只要建个trie然后刷表dp就行了,复杂度最坏是O(字典中最长单词长度*文章长度)的.trie的空间换时间挺不错的. #include ...
- 基于SVG+AJAX的网页数据监控
这个是前一阵做的一个火灾报警主机数据网页监控,前后台主要耗时5小时.绘图2小时,配置后端采集端1小时,测试2小时. 用的SVG,上面画的指示灯可以实时显示传感器的状态. 用开源方案实现. 如果集成到自 ...
- [转]Android中Intent传递对象的两种方法(Serializable,Parcelable)
http://blog.csdn.net/xyz_lmn/article/details/5908355 今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种 ...
- [转]Windows中使用命令行方式编译打包Android项目
http://my.oschina.net/liux/blog/37875 网上很多用Ant来编译打包Android应用的文章,毕竟Ant是纯Java语言编写的,具有很好的跨平台性.今天想写个纯win ...
- mysql_事务
事务是针对数据的,不是针对结构的 存储引擎innodb支持事务,myisam不支持事务需求:有一张银行账户表,有A用户给B账户转账,A账户减少,B账户增加,但是A操作之后断电. 解决方案:A减少钱,但 ...
- 数字签名、数字证书的原理以及证书的获得java版
数字签名原理简介(附数字证书) 首先要了解什么叫对称加密和非对称加密,消息摘要这些知识. 1. 非对称加密 在通信双方,如果使用非对称加密,一般遵从这样的原则:公钥加密,私钥解密.同时,一般一个密钥加 ...
- RouteOS 频繁自启
本来是一个美好的大周末,突然却被一个突如其来的电话把我从美梦中惊醒,然而一切还不止这么简单...... 本来刚开始了解到信息是客户的一台RouteOS设备挂了,听到这个消息时觉得自己应该可以很 ...
- StringBuilder 详解 (String系列之2)
本章介绍StringBuilder以及它的API的详细使用方法. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/string02.html StringB ...
- jquery基于form-data文件上传
1.html代码 <input type="file" name="myupdate" id="myupdate"> 2.jav ...