移动端 transition动画函数的封装(仿Zepto)以及 requestAnimationFrame动画函数封装(仿jQuery)

 

移动端 css3 transition 动画 ,requestAnimationFrame 动画  对于性能的要求,h5优先考虑;

移动端 单页有时候 制作只用到简单的css3动画即可,我们封装一下,没必要引入zepto框架,把zepto的动画模块从Zepto 扒下来,加以改造独立;用于生产环境;下面是 Demo栗子;

上面图片对应的 js

1
2
3
4
5
6
7
8
9
   var leftsbox=document.getElementById("leftsbox");
var boxdiv=leftsbox.getElementsByTagName("div");
leftsbox.onclick=function(){
     for(var i=0;i<boxdiv.length;i++){
               var that=boxdiv[i];
                   transform(that,{ translate3d:'220px,10px,0',left:'1em',opacity:0.2,perspective:'400px', rotateY:'30deg'},800,'cubic-bezier(0.15, 0.5, 0.25, 1.0)',function(){
                         this.innerHTML='结束回调'+this.innerHTML;
                  },100*i);
      } //for

  

再看看另外一种 常见的 如下图

上面对用的 js 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
           var nav=document.querySelector(".nav");
var nava=nav.getElementsByTagName("li");
var content=document.querySelector(".content");
var ulcontent=document.getElementById("ulcontent");
ulcontent.style.width=nav.offsetWidth*nava.length+'px';
for(var i=0;i<nava.length;i++) {
    nava[i].index=i;
    nava[i].onclick=function(){
        var that=this;
        var now=-(that.index)*content.offsetWidth+'px';
 
         transform(ulcontent,{translate3d:''+now+',0,0',},'linear',function(){
        //console.log('success   回调函数');
        })
    }//click end
}

  htm结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<ul class="nav">
           <li ><a >首页</a></li>
           <li ><a >插件</a></li>
           <li ><a >新闻</a></li>
           <li ><a >其他</a></li>
       </ul>
   
    <div class="content">
       <ul id="ulcontent" >
       <li ><img src="../../images/1a.jpg"></li>
       <li ><img src="../../images/2a.jpg"></li>
       <li ><img src="../../images/3a.jpg"></li>
       <li style="background:#ddd;" >44444444444</li>
       </ul>
    </div>

  

基于zepto动画独立出来,原先zepto 动画书写方式

1
2
3
4
5
6
7
8
9
10
11
12
13
$("#banners").animate(
    {
        translate3d:'220px,10px,0',
        left:'1em',
        opacity:0.2,
        perspective:'400px',
        rotateY:'30deg'
    },
    800,
   'cubic-bezier(0.15, 0.5, 0.25, 1.0)',
    function(){  alert('回调'); },
   1000   
)

  

改写后 独立与zepto的 动画函数 语法如下 

transform(dom元素,{ transitionProperty:css值},transitionDuration(单位:毫秒),transitionTiming,transitionend回调,transitionDelay(单位:毫秒)); 

transform(dom元素,animationName,animationDuration(单位:毫秒),animationTiming,animationend回调,animationDelay(单位:毫秒)); 

 

1
2
3
4
5
6
7
8
9
10
/*
* js transfrom
* @param obj {obj}    原生dom对象
* @param properties  {json} ||string     { translate3d:'220px,10px,0',left:'1em',opacity:0.2, rotateY:'30deg'} || animationName 多个可以以逗号分割 如 'fadeIn,sliderDown';
* @param duration {number}      css3持续时间 秒 默认400毫秒
* @param ease {str}           默认linear 支持  cubic-bezier(0.42,0,1,1)写法;
* @param callback {function}    回调函数  
* @param delay {number}    延迟时间   
 
*/

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* http://www.cnblogs.com/surfaces/
    * @param properties 为  {}  或者 string     ;如果 properties= string 为animation-name
    * transform(elem, properties)
    * transform(elem, properties, ease)
    * transform(elem, properties, ease, delay)
    * transform(elem, properties, ease, callback, delay)
    * transform(elem, properties, callback)
    * transform(elem, properties, callback, delay)
    * transform(elem, properties, duration )
    * transform(elem, properties, duration, ease)
    * transform(elem, properties, duration, delay)
    * transform(elem, properties, duration, callback)  
    * transform(elem, properties, duration, callback,delay)  
    * transform(elem, properties, duration, ease, delay)
    * transform(elem, properties, duration, ease, callback)  
    * transform(elem, properties, duration, ease, callback,delay)
     
    transform(elem,{translateX:'150px',left:'1em',opacity:0.2, rotateY:'40deg'},600,'linear',function(){  console.log('结束回调') },200) ;
 
    transform(elem, keyframesName,600,'linear',function(){  console.log('结束回调') },200) ;
*/

  

    

关于兼容性:几乎与zepto一致 ,也支持 动画帧 keyframe,个人觉得  keyframe移动端 兼容性不是很好,尤其手机自带的浏览器(原生app 调用 内嵌H5页面,小问题还是蛮多的),适合无关dom数据操作,只显示美化用;

 

 另外,我们需要了解下  css3 transition-duration的属性写法有多种;如下

1). 过渡单个属性:

1
2
3
4
transition-property:opacity;
transition-duration:2s;
transition-timing-function:ease-in;
transition-delay:0;

  

2). 过渡多个属性:
[1]. 上下一一对应型:
 

1
2
3
4
transition-property:opacity left;
transition-duration:2s, 4s;
transition-timing-function:ease-in;
transition-delay:0;

  

此时:opacity过渡时间为2s,left过渡时间为4s。

[2]. 循环对应型:
 

1
2
3
4
transition-property:opacity left width height;
transition-duration:2s, 4s;
transition-timing-function:ease-in;
transition-delay:0;

  

此时:opacity和width过渡时间为2s,left和height过渡时间为4s。

3). transition简写模式:
顺序为:transition-property transition-duration transition-timing-function transition-delay


  /*单个属性:*/
-moz-transition:background 0.5s ease-out 0s;
/*多个属性:*/
-moz-transition:background, 0.5s ease-out 0s, color 0.4 ease-out 0s;

 

 过渡持续时间
transition-duration 属性规定了一个过渡从初始状态到目标状态的持续时间。它接受以秒或毫秒的值(例如,2.3S和2300ms都是指2.3秒)。
尽管规范明确规定了过渡值必须为正数,但 Opera 仍接受-5S的值,至少对于getComputedStyle()来说是这样的。虽然规范中并没有限制属性值的大小,但 Opera 和 IE 不接受低于10ms的值。而 WebKit 在 getComputedStyle()执行中有个小bug,例如:返回值0.009999999776482582s会取代0.01s。

 

过渡延迟时间
transition-delay 属性规定了在执行一个过渡之前的等待时间,同样使用值。Delay 可以是负值,但这会导致动画无法平滑过渡。
IE 和 Opera 不接受 transition-duration 在-10ms和10ms之间的值。WebKit 的 floating point 也会在这儿出现。

http://www.cnblogs.com/surfaces/ 

 

另外属性相似点 animation-name:keyfrmaes1,keyfrmaes2;以逗号分割;

 其他的

zepto核心动画但是实现了大部分常用的动画;在阅读器zepto核心动画源码的 时候,自己手动封装 实践;就机会发现 看似读懂其实不懂;自己正真封装调试后;才发现哪些巧;

 

封装后的   transform.js  源码如下

 参数说明

1
2
3
4
5
6
7
8
9
10
/*
* js transfrom
* @param obj {obj}    原生dom对象
* @param properties  {json} || string     { translate3d:'220px,10px,0',left:'1em',opacity:0.2,perspective:'400px', rotateY:'30deg'} ||animation-name
* @param duration {number}      css3持续时间 秒 默认400毫秒
* @param ease {str}         transition-timing-function  默认linear 支持  cubic-bezier(0.42,0,1,1)写法;
* @param callback {function}    回调函数  
* @param delay {number}    延迟时间   
 
*/

 使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   /* http://www.cnblogs.com/surfaces/
    * @param properties 为  {}  或者 string     ;如果 properties= string 为animation-name
    * transform(elem, properties)
    * transform(elem, properties, ease)
    * transform(elem, properties, ease, delay)
    * transform(elem, properties, ease, callback, delay)
    * transform(elem, properties, callback)
    * transform(elem, properties, callback, delay)
    * transform(elem, properties, duration )
    * transform(elem, properties, duration, ease)
    * transform(elem, properties, duration, delay)
    * transform(elem, properties, duration, callback)  
    * transform(elem, properties, duration, callback,delay)  
    * transform(elem, properties, duration, ease, delay)
    * transform(elem, properties, duration, ease, callback)  
    * transform(elem, properties, duration, ease, callback,delay)
     
    transform(elem,{translateX:'150px',left:'1em',opacity:0.2,perspective:'400px', rotateY:'40deg'},600,'linear',function(){  console.log('结束回调') },200) ;
    transform(elem, keyframesName,600,'linear',function(){  console.log('结束回调') },200) ;
*/

 移动端 transform.js 源码如下;双击直接复制即可; 

1
;(function(window,document,undefined){var prefix=function(){var div=document.createElement("div");var cssText="-webkit-transition:all .1s;-moz-transition:all .1s; -Khtml-transition:all .1s; -o-transition:all .1s; -ms-transition:all .1s; transition:all .1s;";div.style.cssText=cssText;var style=div.style;var dom="";if(style.webkitTransition){dom="webkit"}else{if(style.MozTransition){dom="moz"}else{if(style.khtmlTransition){dom="Khtml"}else{if(style.oTransition){dom="o"}else{if(style.msTransition){dom="ms"}}}}}div=null;if(dom){return{dom:dom,lowercase:dom,css:"-"+dom+"-",js:dom[0].toUpperCase()+dom.substr(1)}}else{return false}}();var transitionEnd=function(){var el=document.createElement("div");var transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"};for(var name in transEndEventNames){if(el.style[name]!==undefined){return transEndEventNames[name]}}el=null;return false}();var animationEnd=(function(){var eleStyle=document.createElement("div").style;var verdors=["a","webkitA","MozA","OA","msA"];var endEvents=["animationend","webkitAnimationEnd","animationend","oAnimationEnd","MSAnimationEnd"];var animation;for(var i=0,len=verdors.length;i<len;i++){animation=verdors[i]+"nimation";if(animation in eleStyle){return endEvents[i]}}return"animationend"}());var supportedTransforms=/^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i;var dasherize=function(str){return str.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()};function transform(obj,properties,duration,ease,callback,delay){if(!obj){return}if(typeof duration=="undefined"){duration=400;ease="linear";callback=undefined;delay=undefined}if(typeof duration=="string"){if(typeof ease=="number"){delay=ease;callback=undefined}if(typeof ease=="function"){delay=callback;callback=ease}ease=duration;duration=400}else{if(typeof duration=="function"){if(typeof ease=="number"){delay=ease}callback=duration;duration=400;ease="linear"}else{if(typeof duration=="number"){if(typeof ease=="undefined"){ease="linear"}else{if(typeof ease=="string"){ease=ease}else{if(typeof ease=="function"){if(typeof callback=="number"){delay=callback}callback=ease;ease="linear"}else{if(typeof ease=="number"){delay=ease;ease="linear"}}}}if(typeof callback=="number"){delay=callback;callback=undefined}}}}delay=(typeof delay=="number")?delay:0;var endEvent=transitionEnd;var nowTransition=prefix.js+"Transition";var nowTransform=prefix.js+"Transform";var prefixcss=prefix.css;if(!prefix.js){nowTransition="transition";nowTransform="transform";prefixcss=""}var transitionProperty,transitionDuration,transitionTiming,transitionDelay;var animationName,animationDuration,animationTiming,animationDelay;var key,cssValues={},cssProperties,transforms="";var transform;var cssReset={};var css="";var cssProperties=[];transform=prefixcss+"transform";cssReset[transitionProperty=prefixcss+"transition-property"]=cssReset[transitionDuration=prefixcss+"transition-duration"]=cssReset[transitionTiming=prefixcss+"transition-timing-function"]=cssReset[transitionDelay=prefixcss+"transition-delay"]=cssReset[animationName=prefixcss+"animation-name"]=cssReset[animationDuration=prefixcss+"animation-duration"]=cssReset[animationTiming=prefixcss+"animation-timing-function"]=cssReset[animationDelay=prefixcss+"animation-delay"]="";if(typeof properties=="string"){cssValues[animationName]=properties;cssValues[animationDuration]=duration+"ms";cssValues[animationTiming]=(ease||"linear");cssValues[animationDelay]=(delay)+"ms";endEvent=animationEnd}else{endEvent=transitionEnd;for(key in properties){if(supportedTransforms.test(key)){transforms+=key+"("+properties[key]+") "}else{cssValues[key]=properties[key],cssProperties.push(dasherize(key))}}if(transforms){cssValues[transform]=transforms,cssProperties.push(transform)}if(duration>0&&typeof properties==="object"){cssValues[transitionProperty]=cssProperties.join(", ");cssValues[transitionDuration]=duration+"ms";cssValues[transitionTiming]=(ease||"linear");cssValues[transitionDelay]=(delay)+"ms"}}for(var attr in cssValues){css+=dasherize(attr)+":"+cssValues[attr]+";"}obj.style.cssText=obj.style.cssText+";"+css;obj.clientLeft;if(!callback){return}var fired=false;var handler=function(event){if(typeof event!=="undefined"){if(event.target!==event.currentTarget){fired=true;return}}callback&&callback.apply(obj,arguments);fired=true;obj.removeEventListener(endEvent,arguments.callee,false)};if(obj.addEventListener){obj.addEventListener(endEvent,handler,false)}if(!endEvent||duration<=0){setTimeout(function(){handler()});return}setTimeout(function(){if(fired){return}handler()},parseInt((duration+delay)+25))}window.transform=transform})(window,document);

 部分示例 使用代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<style>
*{ margin:0; padding:0;}
ul,li{ list-style:none; margin:0; padding:0;}
 
html{-webkit-touch-callout:none;-webkit-user-select:none;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent; font-size:62.5%; }
body{ font-size:14px;}
 
       
#leftsbox{ width:88%; height:auto; overflow:hidden; border:2px solid red; margin:0 auto; padding:30px 0;}
#leftsbox div{ width:80px; height:80px; background:#6C6; margin-bottom:10px; position:relative; left:0; backface-visibility:hidden; 
-webkit-animation-fill-mode:forwards;
    animation-fill-mode:forwards;
}
 
@keyframes keyframesName{
    0%{ transform:translateX(0)}
    100%{transform:translateX(600px) }
}
@-webkit-keyframes keyframesName{
    0%{ -webkit-transform:translateX(0)}
    100%{-webkit-transform:translateX(600px) }
}
 
    </style>
    <div id="leftsbox">
      <div class="leftssa" style="background:red">1 lefts 22   RAF</div>
      <div class="leftssa " style="width:120px; background:#FF0">2 lefts 22   RAF</div>
      <div class="leftssa"> 333lefts 22   RAF</div>
    </div>
     
<script>
 
      var leftsbox=document.getElementById("leftsbox");
      var boxdiv=leftsbox.getElementsByTagName("div");
      leftsbox.onclick=function(e){
          
           for(var i=0;i<boxdiv.length;i++){
                     var that=boxdiv[i];
             // transform(that,{ translate3d:'220px,10px,0',left:'1em',opacity:0.2,perspective:'400px', width:'200px', rotateY:'30deg'},800,'cubic-bezier(0.15, 0.5, 0.25, 1.0)',function(){
                //  this.innerHTML='结束回调'+this.innerHTML;
            // },1000*i);
                         
                         
                    /*   properties json(css3 属性)  或者 string(css3动画名称)
                      * transform(elem, properties)
                      * transform(elem, properties, ease)
                      * transform(elem, properties, ease, delay)
                      * transform(elem, properties, ease, callback, delay)
                      * transform(elem, properties, callback)
                      * transform(elem, properties, callback, delay)
                      * transform(elem, properties, duration )
                      * transform(elem, properties, duration, ease)
                      * transform(elem, properties, duration, delay)
                      * transform(elem, properties, duration, callback)
                      * transform(elem, properties, duration, callback,delay)  
                      * transform(elem, properties, duration, ease, delay)
                      * transform(elem, properties, duration, ease, callback)  
                      * transform(elem, properties, duration, ease, callback,delay)
                     */
                      
                     //测试 properties为 keyframes
                     var keyframes='keyframesName';
                     //transform(that, keyframes)
                     //transform(that, keyframes,'ease')
                     //transform(that, keyframes,'ease',1000*i)
                     //transform(that, keyframes,'ease',function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i)
                     
                    //transform(that, keyframes,function(){ this.innerHTML='结束回调'+this.innerHTML;})
                    //transform(that, keyframes,function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i)
                     
                    //transform(that, keyframes,600) 
                    //transform(that, keyframes,600,ease')
                    //transform(that, keyframes,600,1000*i) ;
                    //transform(that, keyframes,600,function(){ this.innerHTML='结束回调'+this.innerHTML;}) ; 
                    //transform(that, keyframes,600,function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i) ;
                     
                    //transform(that, keyframes,600,'ease',1000*i)
                    // transform(that, keyframes,600,'ease',function(){ this.innerHTML='结束回调'+this.innerHTML;}) ;
                    // transform(that, keyframes,600,function(){ this.innerHTML='结束回调'+this.innerHTML;},1020*i) ;
                    // transform(that, keyframes,600,function(){ this.innerHTML='结束回调'+this.innerHTML;},-20*i) ; //css3 animation-delay 支持负数 直接进入到时间点
                     
                     //测试 properties为 Json
                     var json={translate3d:'600px,10px,0',left:'1em',opacity:0.2,perspective:'400px', width:'200px', rotateY:'30deg'}
                     //transform(that,json);
                      // transform(that, json,'ease')
                     //transform(that, json,'ease',1000*i)
                     //transform(that, json,'ease',function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i)
                     
                    //transform(that, json,function(){ this.innerHTML='结束回调'+this.innerHTML;})
                    //transform(that, json,function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i)
                     
                    //transform(that, json,600) 
                    //transform(that, json,600,'ease')
                    //transform(that, json,600,1000*i) ;
                    //transform(that, json,600,function(){ this.innerHTML='结束回调'+this.innerHTML;}) ; 
                    // transform(that, json,600,function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i) ;
                     
                    //transform(that, json,600,'ease',1000*i)
                    //transform(that, json,600,'ease',function(){ this.innerHTML='结束回调'+this.innerHTML;}) ;
                    transform(that, json,600,'ease',function(){ this.innerHTML='结束回调'+this.innerHTML;},1000*i) ;
                    //transform(that, json,600,'ease',function(){ this.innerHTML='结束回调'+this.innerHTML;},-100*i) ; ////css3 transition-delay 支持负数 直接进入到时间点
                     
                        
            } //for end
          
      }            
</script>

  

唯一的缺点  scrollTop 缓动不支持; 这里有个简易的  函数 类似jquery  语法几乎一样 基于时间 算法 使用 requestAnimationFrame  

先看效果

 

相关布局

复制代码
<ul id="inner" >
        <li><a class="on" >护肤</a></li>
        <li><a >彩妆</a></li>
        <li><a >洗护</a></li>
        <li><a >套装</a></li>
    </ul>
    
     <ul class="uls" id="uls">
        <li id='li1'></li>
         <li id='li12'></li>
         <li id='li3'></li>
  
 </ul>

    
    
 <div class="box22">
 <div class="boxs">1111111111111111111111111111111111</div>
  <div class="boxs">22222222222222222222222222222</div>
  
   <div class="boxs">33333333333333333333333</div>
  <div class="boxs" style="height:100px;">4444444444444444444最后一个 </div>
 </div>
 
 
 <div id="gpTop">tops</div>
复制代码

 

 

上图相关js

复制代码
  document.getElementById("gpTop").onclick=function(e){
              var  that=this;
                 startMove(that,{"scrollTop":0},function(){
                    that.innerHTML='到顶了';
                     });  //width: 206px; height: 101px; opacity: 0.3;
                }
                
                
                var inner=document.getElementById("inner");
                var inlione=inner.getElementsByTagName("li");
                var box=document.querySelectorAll(".boxs");
                
                for(var i=0;i<inlione.length;i++) {  
                 inlione[i].index=i;
                 inlione[i].onclick=function(e){
                 var that=this;
                // console.log(that.index);
                 var box2=box[that.index];
                 var nowTop=getOffest(box2).top;
                // console.log(nowTop);
                 
                  animate(window,{"scrollTop":nowTop},function(){
                    //console.log('success');
                    });
           }
             
        }
复制代码

如果通过原生js  获取  jquey的offset().top  的值呢 如下  这里

复制代码
  
var getOffest=function (obj){
var top=0,left=0;
if(obj){
 while(obj.offsetParent){
      top += obj.offsetTop;
      left += obj.offsetLeft;
      obj = obj.offsetParent;
   }
 }

  return{
  top : top,
  left : left
  }
}
复制代码

 

animate.js基于 requestAnimationFrame  兼容ie8+    (单位px  未做rem 兼容处理 ,没有jquery的 stop()处理)

语法如下

 

animate(dom元素,{"left":1300,"opacity":90},持续时间(毫秒),缓动形式(tween函数),回调函数);

1
2
3
animate(element,{"left":1300,"opacity":90},2000,'easeOut',function sa(){
 console.log('回调函数');
}); 

 

为什么要用   requestAnimationFrame  。

浏览器可以优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果。比如,通过requestAnimationFrame(),JS动画能够和CSS动画/变换或SVG SMIL动画同步发生。另外,如果在一个浏览器标签页里运行一个动画,当这个标签页不可见时,浏览器会暂停它,这会减少CPU,内存的压力,节省电池电量。

相信日后  requestAnimationFrame 在移动端发展的前景是相当不错的,目前安卓上感觉还是有点丢帧。抖动明显;

 

requestAnimationFrame  一个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var start = null;
var ele = document.getElementById("j_precent");
var progress = 0;
 
function step() {
    progress += 1;
    ele.style.width = progress + "%";
    ele.innerHTML=progress + "%";
    if (progress < 100) {
        requestAnimationFrame(step);
    }
}
 
document.getElementById("btn_run").addEventListener("click", function() {
    ele.style.width = "1px";
    progress = 0;
     step()
}, false);

  

如下   jQuery1.6.2还用 requestAnimationFrame;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Start an animation from one number to another
custom: function( from, to, unit ) {
    var self = this,
        fx = jQuery.fx,
        raf;
 
    this.startTime = fxNow || createFxNow();
    this.start = from;
    this.end = to;
    this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
    this.now = this.start;
    this.pos = this.state = 0;
 
    function t( gotoEnd ) {
        return self.step(gotoEnd);
    }
 
    t.elem = this.elem;
 
    if ( t() && jQuery.timers.push(t) && !timerId ) {
        // Use requestAnimationFrame instead of setInterval if available
        if ( requestAnimationFrame ) {
            timerId = true;
            raf = function() {
                // When timerId gets set to null at any point, this stops
                if ( timerId ) {
                    requestAnimationFrame( raf );
                    fx.tick();
                }
            };
            requestAnimationFrame( raf );
        } else {
            timerId = setInterval( fx.tick, fx.interval );
        }
    }
},

  http://stackoverflow.com/questions/7999680/why-doesnt-jquery-use-requestanimationframe

为啥jquery 放弃,上面说的比较完善;

 

animate源码如下

复制代码
;(function() {

  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];

  for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(function() { callback(currTime + timeToCall); },
        timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  }

  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
      clearTimeout(id);
    };
  }

}());

var getStyle=function (obj,attr){
    return obj.currentStyle ? obj.currentStyle[attr]:getComputedStyle(obj)[attr];
}    
      
var Tween = {
    linear: function (t, b, c, d){  //匀速
        return c*t/d + b;
    },
    easeIn: function(t, b, c, d){  //加速曲线
        return c*(t/=d)*t + b;
    },
    easeOut: function(t, b, c, d){  //减速曲线
        return -c *(t/=d)*(t-2) + b;
    },
    easeBoth: function(t, b, c, d){  //加速减速曲线
        if ((t/=d/2) < 1) {
            return c/2*t*t + b;
        }
        return -c/2 * ((--t)*(t-2) - 1) + b;
    },
    easeInStrong: function(t, b, c, d){  //加加速曲线
        return c*(t/=d)*t*t*t + b;
    },
    easeOutStrong: function(t, b, c, d){  //减减速曲线
        return -c * ((t=t/d-1)*t*t*t - 1) + b;
    },
    easeBothStrong: function(t, b, c, d){  //加加速减减速曲线
        if ((t/=d/2) < 1) {
            return c/2*t*t*t*t + b;
        }
        return -c/2 * ((t-=2)*t*t*t - 2) + b;
    },
    elasticIn: function(t, b, c, d, a, p){  //正弦衰减曲线(弹动渐入)
        if (t === 0) { 
            return b; 
        }
        if ( (t /= d) == 1 ) {
            return b+c; 
        }
        if (!p) {
            p=d*0.3; 
        }
        if (!a || a < Math.abs(c)) {
            a = c; 
            var s = p/4;
        } else {
            var s = p/(2*Math.PI) * Math.asin (c/a);
        }
        return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
    },
    elasticOut: function(t, b, c, d, a, p){    //正弦增强曲线(弹动渐出)
        if (t === 0) {
            return b;
        }
        if ( (t /= d) == 1 ) {
            return b+c;
        }
        if (!p) {
            p=d*0.3;
        }
        if (!a || a < Math.abs(c)) {
            a = c;
            var s = p / 4;
        } else {
            var s = p/(2*Math.PI) * Math.asin (c/a);
        }
        return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
    },    
    elasticBoth: function(t, b, c, d, a, p){
        if (t === 0) {
            return b;
        }
        if ( (t /= d/2) == 2 ) {
            return b+c;
        }
        if (!p) {
            p = d*(0.3*1.5);
        }
        if ( !a || a < Math.abs(c) ) {
            a = c; 
            var s = p/4;
        }
        else {
            var s = p/(2*Math.PI) * Math.asin (c/a);
        }
        if (t < 1) {
            return - 0.5*(a*Math.pow(2,10*(t-=1)) * 
                    Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
        }
        return a*Math.pow(2,-10*(t-=1)) * 
                Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
    }
}




function animate(obj,json,times,fx,fn){
    
    if( typeof times == 'undefined' ){
        times = 400;
        fx = 'linear';
    }
    
    if( typeof times == 'string' ){
        if(typeof fx == 'function'){
            fn = fx;
        }
        fx = times;
        times = 400;
    }
    else if(typeof times == 'function'){
        fn = times;
        times = 400;
        fx = 'linear';
    }
    else if(typeof times == 'number'){
        if(typeof fx == 'function'){
            fn = fx;
            fx = 'linear';
        }
        else if(typeof fx == 'undefined'){
            fx = 'linear';
        }
    }
    
    

    var iCur = {};
    var startTime = +new Date();
    
    for(var attr in json){
        iCur[attr] = 0;
        
        if( attr == 'opacity' ){
            if(Math.round(getStyle(obj,attr)*100) == 0){
                iCur[attr] = 0;
            }
            else{
                iCur[attr] = Math.round(getStyle(obj,attr)*100) || 100;
            }
        }
        else if(attr == 'scrollTop' ){
                 iCur[attr]=window.scrollY||document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;;         
            }
        else{
            iCur[attr] = parseInt(getStyle(obj,attr)) || 0;
        }
        
    }
    
    
        if(obj.timer){
        cancelAnimationFrame(obj.timer)
        }
        //obj.timer=null;
    
    function update(){    
        
        var changeTime = +new Date();
        var scale = 1 - Math.max(0,startTime - changeTime + times)/times;
        
        for(var attr in json){
            
            var value = Tween[fx](scale*times, iCur[attr] , json[attr] - iCur[attr] , times );
            
            if(attr == 'opacity'){
                obj.style.filter = 'alpha(opacity='+ value +')';
                obj.style.opacity = value/100;
            }else if(attr == 'scrollTop'){
                 window.scrollTo(0, value); 
           }else{
                obj.style[attr] = value + 'px';
            }
            
        }
        
        if(scale == 1){
                cancelAnimationFrame(obj.timer);
                 fn&&fn.apply(this, arguments);
        }else{
             //setup_fps_meters();
            obj.timer=requestAnimationFrame(arguments.callee);
            }
        
   }//update  end
   //    requestAnimationFrame(update);  //某些时候 画的过快  有bug
    update();
    
}    
    
    
复制代码
复制代码
Tween.js  
/*

* t : time 已过时间
* b : begin 起始值
* c : count 总的运动值
* d : duration 持续时间
* */
 
//Tween.linear();
复制代码

 

 

css cubic-bezier 缓动备份查看  注意点:x1,x2,y1,y2的值范围在[0, 1]。

复制代码
var easingMap = {
  "linear": [0.250, 0.250, 0.750, 0.750],
  "ease": [0.250, 0.100, 0.250, 1.000],
  "easeIn": [0.420, 0.000, 1.000, 1.000],
  "easeOut": [0.000, 0.000, 0.580, 1.000],
  "easeInOut": [0.420, 0.000, 0.580, 1.000],
  "easeInQuad": [0.550, 0.085, 0.680, 0.530],
  "easeInCubic": [0.550, 0.055, 0.675, 0.190],
  "easeInQuart": [0.895, 0.030, 0.685, 0.220],
  "easeInQuint": [0.755, 0.050, 0.855, 0.060],
  "easeInSine": [0.470, 0.000, 0.745, 0.715],
  "easeInExpo": [0.950, 0.050, 0.795, 0.035],
  "easeInCirc": [0.600, 0.040, 0.980, 0.335],
  "easeInBack": [0.600, -0.280, 0.735, 0.045],
  "easeOutQuad": [0.250, 0.460, 0.450, 0.940],
  "easeOutCubic": [0.215, 0.610, 0.355, 1.000],
  "easeOutQuart": [0.165, 0.840, 0.440, 1.000],
  "easeOutQuint": [0.230, 1.000, 0.320, 1.000],
  "easeOutSine": [0.390, 0.575, 0.565, 1.000],
  "easeOutExpo": [0.190, 1.000, 0.220, 1.000],
  "easeOutCirc": [0.075, 0.820, 0.165, 1.000],
  "easeOutBack": [0.175, 0.885, 0.320, 1.275],
  "easeInOutQuad": [0.455, 0.030, 0.515, 0.955],
  "easeInOutCubic": [0.645, 0.045, 0.355, 1.000],
  "easeInOutQuart": [0.770, 0.000, 0.175, 1.000],
  "easeInOutQuint": [0.860, 0.000, 0.070, 1.000],
  "easeInOutSine": [0.445, 0.050, 0.550, 0.950],
  "easeInOutExpo": [1.000, 0.000, 0.000, 1.000],
  "easeInOutCirc": [0.785, 0.135, 0.150, 0.860],
  "easeInOutBack": [0.680, -0.550, 0.265, 1.550],
  "custom": [0.000, 0.350, 0.500, 1.300],
  "random": [Math.random().toFixed(3),
      Math.random().toFixed(3),
      Math.random().toFixed(3),
      Math.random().toFixed(3)]
    }
复制代码

This curve contains values out of range. But fear not young padawan! Just use cubic-bezier(.25,.1,.39,1) as well for Webkit until the bug #45761 fix propagates to Safari.

 接近ios 原生 的切换 cubic-bezier(0.42, 0, 0.58, 1.0)

http://www.cnblogs.com/surfaces/

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 // transform兼容
    function preTransform() {
        var cssPrefix,
        vendors = {
          '': '',
          Webkit: 'webkit',
          Moz: '',
          O: 'o',
          ms: 'ms'
        },
        testEle = document.createElement('p'),
        cssSupport = {};
  
         // 嗅探特性
        Object.keys(vendors).some(function(vendor) {
            if (testEle.style[vendor + (vendor ? 'T' : 't') + 'ransform'] !== undefined) {
              cssPrefix = vendor ? '-' + vendor.toLowerCase() + '-' : '';
              return true;
            }
        });
  
      function normalizeCss(name) {
        name = name.toLowerCase();
        return cssPrefix ? cssPrefix + name : name;
      }
  
      cssSupport = {
        transform: normalizeCss('Transform'),
      }
  
      return cssSupport.transform;
    }
}());

 

 

 使用tween 单独的 , easeIn1 自定义的,

var easeIn1= Tween.easeIn=function(t, b, c, d){  //加速曲线
        return c*(t/=d)*t + b;
    }

 

https://stackoverflow.com/questions/8917921/cross-browser-javascript-not-jquery-scroll-to-top-animation/16136789#16136789

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
document.getElementById("asdad").onclick = function() {
                    function easeInOutQuad(t, b, c, d) {
                        t /= d / 2;
                        if (t < 1) return c / 2 * t * t + b;
                        t--;
                        return -c / 2 * (t * (t - 2) - 1) + b;
                    };
 
                    function easeIn1(currentTime, start, change, duration) {
                        currentTime /= duration / 2;
                        if (currentTime < 1) {
                            return change / 2 * currentTime * currentTime + start;
                        }
                        currentTime -= 1;
                        return -change / 2 * (currentTime * (currentTime - 2) - 1) + start;
                    }
                    console.log("body goTop", document.scrollingElement.scrollTop)
                    //  scrollTo(document.scrollingElement, 0, 1250,easeIn1); 
                    scrollTo(document.scrollingElement, 100, 1250, easeIn1);
                }
 
 
 
                function scrollTo(element, to, duration, easefn) {
                    var start = element.scrollTop,
                        change = to - start,
                        increment = 20;
                    var easefn = easefn
                    //console.log(start,document.body.scrollTop,easefn===easeInOut,"easefn",typeof easefn)
                    var animateScroll = function(elapsedTime) {
                        elapsedTime += increment;
                        var position = easefn(elapsedTime, start, change, duration);
                        element.scrollTop = position;
                        if (elapsedTime < duration) {
                            setTimeout(function() {
                                animateScroll(elapsedTime);
                            }, increment);
                        }
                    };
 
                    animateScroll(0);
                }

  

 

 

示例

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width" />
 
        <title>scrollAnimate</title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
 
        ul,
        li {
            margin: 0;
            padding: 0;
            list-style: none;
        }
 
 
 
        .scroll-box {
            background-color: #EEEEEE;
            border: 1px solid red;
            height: 500px;
            overflow-y: hidden;
            touch-action: pan-y;
            ;
        }
 
        .scroll-box p {
            min-height: 50px;
            ;
        }
 
        .scroll-box p:nth-child(odd) {
            background-color: #999;
        }
    </style>
    <body>
 
 
        <p style="margin: 20px auto;  text-align: center;">------ -------start- <button
                id="j_dom">点击观察</button>-----------------</p>
 
        <div class="scroll-box " id="j_target" style="width: 80%; height: 400px;; margin: 0 auto;">
 
            <p style="height: 100px;background-color: red;;">111111111111111</p>
            <p>22222</p>
            <p style="height: 600px;background-color: #ddd;;">33</p>
            <p>44</p>
            <p style="height: 100px; background-color: red;">55</p>
 
 
        </div>
 
        <p style="margin: 20px auto;  text-align: center;">------ -------end------------------</p>
        <script>
            window.onload = function() {
                function getArrlist(len, height) {
                    var strHtml = ""
                    var len = 500;
                    var height = 100;
                    for (var i = 0; i < len; i++) {
                        var str = '';
                        if (i == 0) {
                            str = "开始"
                        } else
                        if (i == len - 1) {
                            str = "最后"
                        } else {
                            str = i
                        }
                        strHtml += '<p index="' + i + '">' + str + '</p>'
 
                    }
                    return strHtml;
                }
 
                function moveTo(element, start, to, prop, duration, easing, endFn, stepFn) {
                    var prop = prop;
                    var start = start || 0;
                    var change = to - start;
                    var duration = duration;
                    var easeInOut = easing;
                    var increment = 13;
 
                    console.log("moveTo", start, "easefn", easeInOut)
                    var animateScroll = function(elapsedTime) {
                        elapsedTime += increment;
                        var value = easeInOut(elapsedTime, start, change, duration);
                        element.style[prop] = value + 'px';
                        stepFn && stepFn.call(this, value);
                        if (elapsedTime < duration) {
                            setTimeout(function() {
                                animateScroll(elapsedTime);
                            }, increment);
                        } else {
                            element.style[prop] = to + 'px';
                            endFn && endFn.call(this, value);
                        }
                    };
 
                    animateScroll(0);
                }
 
                function scrollAnimate(element, start, to, prop, duration, easing, endFn, stepFn) {
 
                    var prop = prop;
                    var start = start || 0;
                    var change = parseInt(to - start)
                    var duration = duration;
                    var easeInOut = easing;
                    var startTime = (+new Date);
                    //var currentY= parseInt(element.scrollTop);
 
 
                    console.log("scrollAnimate", start, "easefn", easeInOut)
                    step();
 
                    //结束时间的计算
                    function step() {
                        var changeTime = +new Date();
                        var scale = 1 - Math.max(0, startTime - changeTime + duration) / duration;
 
 
                        var value = easeInOut(scale * duration, start, change, duration);
                        // var easingFunc = BezierEasing(.42, 0, 1, 1);
                        // var percent = easingFunc(scale);
                        // var value = start + to * percent;
                        //console.log("scrollAnimate", scale, "percent", percent)
 
                        // var value = Tween[easing](scale*duration,targetY,change,duration);
                        //var value = easeInOut(scale * duration, start, change, duration);
 
                        //console.log("scale",scale,"已过时间",(changeTime-startTime),"总时间",duration,"已过时间百分比",(changeTime-startTime)/duration,'change距离',change)
                        // console.log(value,"scale",scale,"已过时间百分比",(changeTime-startTime)/duration,'change距离',change)
                        //得到新的坐标值后我们继续通过left/top或者transform来完成计算就可以了
                        element.style[prop] = value + 'px';
                        stepFn && stepFn.call(this, value);
                        if (scale == 1) {
                            // console.log("运动结束");
                            cancelAnimationFrame(element.timer);
                            endFn && endFn.call(this, value);
                            return;
                        } else {
                            element.timer = requestAnimationFrame(step);
                        }
 
                    }
                    //https://github.com/alvarotrigo/fullPage.js/blob/master/src/fullpage.js
                }
 
 
                function easeInOutQuad(t, b, c, d) {
                    t /= d / 2;
                    if (t < 1) return c / 2 * t * t + b;
                    t--;
                    return -c / 2 * (t * (t - 2) - 1) + b;
                };
 
                var j_target = document.getElementById("j_target");
                var j_dom = document.getElementById("j_dom")
                j_target.innerHTML = getArrlist();
                j_target.scrollTop = 100;
                j_dom.addEventListener("click", function() {
                    console.log("click ", j_target);
                    //scrollAnimate(element, start, to, prop, duration, easing, endFn, stepFn)
 
                    scrollAnimate(j_target, 0, 1200, "scrollTop", 1400, easeInOutQuad, function() {
                        //console.log("外面运动中");
 
                    }, function(val) {
                        j_target.scrollTop = val;
                        console.log("外面运动中");
                    })
 
                    return false;
                })
            }
        </script>
        <script>
 
        </script>
 
    </body>

  

 

 

 

 

  

BezierEasing 开源库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
 * https://github.com/gre/bezier-easing
 * BezierEasing - use bezier curve for transition easing function
 * by Gaëtan Renaudeau 2014 - 2015 – MIT License
 */
 
// These values are established by empiricism with tests (tradeoff: performance VS precision)
var NEWTON_ITERATIONS = 4;
var NEWTON_MIN_SLOPE = 0.001;
var SUBDIVISION_PRECISION = 0.0000001;
var SUBDIVISION_MAX_ITERATIONS = 10;
 
var kSplineTableSize = 11;
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
 
var float32ArraySupported = typeof Float32Array === 'function';
 
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C (aA1)      { return 3.0 * aA1; }
 
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
 
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
 
function binarySubdivide (aX, aA, aB, mX1, mX2) {
  var currentX, currentT, i = 0;
  do {
    currentT = aA + (aB - aA) / 2.0;
    currentX = calcBezier(currentT, mX1, mX2) - aX;
    if (currentX > 0.0) {
      aB = currentT;
    } else {
      aA = currentT;
    }
  } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
  return currentT;
}
 
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
 for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
   var currentSlope = getSlope(aGuessT, mX1, mX2);
   if (currentSlope === 0.0) {
     return aGuessT;
   }
   var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
   aGuessT -= currentX / currentSlope;
 }
 return aGuessT;
}
 
function LinearEasing (x) {
  return x;
}
 
module.exports = function bezier (mX1, mY1, mX2, mY2) {
  if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
    throw new Error('bezier x values must be in [0, 1] range');
  }
 
  if (mX1 === mY1 && mX2 === mY2) {
    return LinearEasing;
  }
 
  // Precompute samples table
  var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
  for (var i = 0; i < kSplineTableSize; ++i) {
    sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
  }
 
  function getTForX (aX) {
    var intervalStart = 0.0;
    var currentSample = 1;
    var lastSample = kSplineTableSize - 1;
 
    for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
      intervalStart += kSampleStepSize;
    }
    --currentSample;
 
    // Interpolate to provide an initial guess for t
    var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
    var guessForT = intervalStart + dist * kSampleStepSize;
 
    var initialSlope = getSlope(guessForT, mX1, mX2);
    if (initialSlope >= NEWTON_MIN_SLOPE) {
      return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
    } else if (initialSlope === 0.0) {
      return guessForT;
    } else {
      return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
    }
  }
 
  return function BezierEasing (x) {
    // Because JavaScript number are imprecise, we should guarantee the extremes are right.
    if (x === 0 || x === 1) {
      return x;
    }
    return calcBezier(getTForX(x), mY1, mY2);
  };
};

  

var easing = BezierEasing(0, 0, 1, 0.5);
// easing allows to project x in [0.0,1.0] range onto the bezier-curve defined by the 4 points (see schema below).
console.log(easing(0.0)); // 0.0
console.log(easing(0.5)); // 0.3125
console.log(easing(1.0)); // 1.0

 

 

 

 腾讯的一个例子 http://alloyteam.github.io/AlloyFinger/example/picture/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var To=function (el, property, value, time, ease, onEnd,onChange ) {
    var current = el[property];
    var dv = value - current;
    var beginTime = new Date();
    var self = this;
    var currentEase=ease||function(a){return a };
    this.tickID=null;
    var toTick = function () {
        var dt = new Date() - beginTime;
        if (dt >= time) {
            el[property] = value;
            onChange && onChange(value);
            onEnd && onEnd(value);
            cancelAnimationFrame(self.tickID);
            self.toTick=null;
            return;
        }
        el[property] = dv * currentEase(dt / time) + current;
        self.tickID=requestAnimationFrame(toTick);
        //self.tickID = requestAnimationFrame(toTick);
        //cancelAnimationFrame������ tickID = requestAnimationFrame(toTick);�ĺ���
        onChange && onChange(el[property]);
    };
    toTick();
    To.List.push(this);
};
 
To.List=[];
 
To.stopAll=function(){
    for(var i= 0,len=To.List.length;i<len;i++){
        cancelAnimationFrame(To.List[i].tickID);
    }
    To.List.length=0;
};
 
To.stop=function(to) {
    cancelAnimationFrame(to.tickID);
};

  

 

调用方式     new To(el, "translateX", x, 500, ease);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<!DOCTYPE html>
<html>
<head>
    <title>AlloyFinger</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
    <style>
        .ribbon {
            top: 3.2em;
            right: -4.7em;
            -webkit-transform: rotate(45deg);
            -moz-transform: rotate(45deg);
            -ms-transform: rotate(45deg);
            -o-transform: rotate(45deg);
            transform: rotate(45deg);
            color:#fff;
            display: block;
            padding: .6em 3.5em;
            position: fixed;
            text-align: center;
            text-decoration: none;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            background-color: green;
            z-index: 10000;
        }
    </style>
</head>
<body>
    <a href="https://github.com/AlloyTeam/AlloyFinger" class="ribbon">Fork me on Github</a>
    <script src="../../asset/transform.js"></script>
    <script src="../../alloy_finger.js"></script>
    <script src="../../asset/image_loaded.js"></script>
    <script src="../../asset/to.js"></script>
    <div id="imgBox" style="position:fixed;width: 100%;height: 100%;left:0;top:0;
     background:black;display: none;">
        <img src="../../asset/cover.jpg" id="testImg" alt="" style="width: 100%;position: absolute; " />
    </div>
 
    <script>
        var topPx;
        imageLoaded("#testImg",function(w,h){
            document.querySelector("#imgBox").style.display="block";
            topPx=window.innerHeight/2-(h*window.innerWidth/w)/2;
            this.style.top=topPx+"px";
        });
 
 
        function ease(x) {
            return Math.sqrt(1 - Math.pow(x - 1, 2));
        }
 
        var el = document.getElementById("testImg");
        Transform(el);
        var initScale = 1;
        new AlloyFinger(el, {
            multipointStart: function () {
                To.stopAll();
                initScale = el.scaleX;
            },
            rotate: function (evt) {
                el.rotateZ += evt.angle;
            },
            pinch: function (evt) {
                el.scaleX = el.scaleY = initScale * evt.zoom;
            },
            multipointEnd: function () {
                To.stopAll();
                if (el.scaleX < 1) {
 
                    new To(el, "scaleX", 1, 500, ease);
                    new To(el, "scaleY", 1, 500, ease);
                }
                if (el.scaleX > 2) {
 
                    new To(el, "scaleX", 2, 500, ease);
                    new To(el, "scaleY", 2, 500, ease);
                }
                var rotation = el.rotateZ % 360;
 
                if (rotation < 0)rotation = 360 + rotation;
                el.rotateZ=rotation;
 
                if (rotation > 0 && rotation < 45) {
                    new To(el, "rotateZ", 0, 500, ease);
                } else if (rotation >= 315) {
                    new To(el, "rotateZ", 360, 500, ease);
                } else if (rotation >= 45 && rotation < 135) {
                    new To(el, "rotateZ", 90, 500, ease);
                } else if (rotation >= 135 && rotation < 225) {
                    new To(el, "rotateZ", 180, 500, ease);
                } else if (rotation >= 225 && rotation < 315) {
                    new To(el, "rotateZ", 270, 500, ease);
                }
            },
            pressMove: function (evt) {
                el.translateX += evt.deltaX;
                el.translateY += evt.deltaY;
                evt.preventDefault();
            },
            tap: function (evt) {
                //console.log(el.scaleX + "_" + el.scaleY + "_" + el.rotateZ + "_" + el.translateX + "_" + el.translateY);
                //console.log("tap");
            },
            doubleTap: function (evt) {
                To.stopAll();
                if (el.scaleX > 1.5) {
 
                    new To(el, "scaleX", 1, 500, ease);
                    new To(el, "scaleY", 1, 500, ease);
                    new To(el, "translateX", 0, 500, ease);
                    new To(el, "translateY", 0, 500, ease);
                } else {
                    var box = el.getBoundingClientRect();
                    var y = box.height - (( evt.changedTouches[0].pageY - topPx) * 2) - (box.height / 2 - ( evt.changedTouches[0].pageY - topPx));
 
                    var x = box.width - (( evt.changedTouches[0].pageX) * 2) - (box.width / 2 - ( evt.changedTouches[0].pageX));
                    new To(el, "scaleX", 2, 500, ease);
                    new To(el, "scaleY", 2, 500, ease);
                    new To(el, "translateX", x, 500, ease);
                    new To(el, "translateY", y, 500, ease);
                }
                //console.log("doubleTap");
            },
            longTap: function (evt) {
                //console.log("longTap");
            },
            swipe: function (evt) {
                //console.log("swipe" + evt.direction);
            }
 
        });
 
    </script>
</body>
</html>

  

 

 参考资料:

snabbt.js

 http://daniel-lundin.github.io/snabbt.js/index.html

jquery.transit.js

Zepto.js

Bootstrap.transition.js jquery.js

 


posted @   surfaces  阅读(4850)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示