码迷,mamicode.com
首页 > 移动开发 > 详细

移动端 动画函数 的 封装

时间:2016-01-14 14:14:53      阅读:264      评论:0      收藏:0      [点我收藏+]

标签:

 

移动端 单页有时候 制作只用到简单的css3动画即可,我们简单封装一下,没必要引入zepto框架。

技术分享

上面图片对应的 js

         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 代码

  
                       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结构

 <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 动画

$("#some_element").animate(
    {
        opacity:0.25,
        left:‘50px‘,
        color:‘#abcdef‘,
        rotateZ:‘45deg‘,
        translate3d:‘0,10px,0‘
    },
    500,
    ‘ease-out‘,function(){  alert(‘回调‘); }
)

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

transform(element,{ translate3d:‘220px,10px,0‘,left:‘1em‘,opacity:0.2,perspective:‘400px‘, rotateY:‘30deg‘},duration,‘linear‘,fn,delay);

  关于兼容性:几乎与zepto一致 ,但是不支持 动画帧 keyframe,个人觉得  keyframe移动端 兼容性不是很好,尤其手机自带的浏览器(原生app 调用 内嵌H5页面,小问题还是蛮多的);

 

     

源码如下

 
//transform(obj,{translateX:‘150px‘,left:‘1em‘,opacity:0.2,perspective:‘400px‘, rotateY:‘40deg‘},duration,‘linear‘,fn,delay);

               
				
;(function(window,document,undefined){

var prefix = function() {
  var div = document.createElement(‘div‘);//建立临时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‘;
  }
  if (style.MozTransition) {
    dom=‘moz‘;
  }
   if (style.khtmlTransition) {
    dom=‘Khtml‘;
  }
  
  if (style.oTransition) {
    dom=‘o‘;
  }
  if (style.msTransition) {
    dom=‘ms‘;
  }
 
  div=null; ////去掉不必要的数据存储,便于垃圾回收 

  if(dom){////style.transition 情况
	  return {
		dom: dom,
		lowercase: dom,
		css: ‘-‘ + dom + ‘-‘,
		js: dom[0].toUpperCase() + dom.substr(1)
	  }; 
  }else{
	  return false;  
 }
}();

//alert(prefix.js);

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;
  
}();

//alert(‘支持‘+transitionEnd);
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‘) //在大小写字符之间插入_,大写在前,比如AAAbb,得到AA_Abb
    .replace(/([a-z\d])([A-Z])/g, ‘$1_$2‘) //在大小写字符之间插入_,小写或数字在前,比如bbbAaa,得到bbb_Aaa
    .replace(/_/g, ‘-‘) //将_替换成-
    .toLowerCase() //转成小写
  }





var transform=function (obj,properties, duration, ease, callback, delay){
	
	
	 if (!obj) return;
	//参数修正
	
	  if (typeof duration == ‘function‘)
      callback = duration, ease = undefined, duration = 400,delay=delay
      if (typeof ease == ‘function‘)  //传参为function(properties,duration,callback)
        callback = ease, ease = undefined,delay=delay
     
      if (duration) duration = typeof duration == ‘number‘ ? duration :400;
	
	  delay = (typeof delay == ‘number‘) ? delay :0;
	  
     
	//参数修正
	var nowTransition=prefix.js+‘Transition‘;
	var nowTransform=prefix.js+‘Transform‘;
	var prefixcss=prefix.css;
	if(!prefix.js){
		nowTransition=‘transition‘;
	    nowTransform=‘transform‘;
		prefixcss=‘‘;  //-webkit-transition >> transition  
	}
	
	var transitionProperty, transitionDuration, transitionTiming, transitionDelay;//过渡
	var key, cssValues = {}, cssProperties, transforms = "";    // transforms 变形   cssValues设置给DOM的样式
	var transform;     //变形
    var cssReset = {};
	var css=‘‘;
	var cssProperties = [];
	
	
	  transform = prefixcss + ‘transform‘;       //变形    cssValues[transform]
	  cssReset[transitionProperty = prefixcss + ‘transition-property‘] =
	  cssReset[transitionDuration = prefixcss + ‘transition-duration‘] =
	  cssReset[transitionDelay    = prefixcss + ‘transition-delay‘] =
	  cssReset[transitionTiming   = prefixcss + ‘transition-timing-function‘]=‘‘;
	
	
      // CSS transitions
	
     for (key in properties){
       //如果设置 的CSS属性是变形之类的
       if (supportedTransforms.test(key)) transforms += key + ‘(‘ + properties[key] + ‘) ‘
       else cssValues[key] = properties[key], cssProperties.push(dasherize(key))
	 } //for end 
       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;	
			
		    	  
		if(!callback){return } //没有回调函数 return

	    var fired = false;
		var handler = function () {

				 callback && callback.apply(obj,arguments);
				 fired=true;
				  
				if(obj.removeEventListener)
				 obj.removeEventListener(transitionEnd,arguments.callee,false)				
        };
          
		  if(obj.addEventListener){
	       obj.addEventListener(transitionEnd, handler,false);
		  }
		

		  if(!transitionEnd||duration<=0){ //没有  @1 transitionEnd 事件    或者@2 duration为0,即浏览器不支持动画的情况  直接执行动画结束,执行回调。     
			 setTimeout(function(){
			 handler();
			 });
			return;
		  }
		   
		
		
		 setTimeout(function(){//绑定过事件还做延时处理,是transitionEnd在older Android phones不一定触发
			    if(fired) return
				  handler()	
		},(duration + delay) + 25);
		
							  
}//end

   window.transform=transform;

})(window,document);

  

 唯一的缺点  scrollTop 缓动不支持; 这里有个简易的  函数 类似jquery  语法几乎一样

先看效果

技术分享

 

相关布局

<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);
                 
                  startMove(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
  }
}

 

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

语法如下

 

			  startMove(element,{"left":1300,"opacity":90},2000,‘easeOut‘,function sa(){
			  console.log(‘回调函数‘);
			 });  //  width: 201px; height: 135px; opacity: 0.8;  只有宽是对的  其他未达到目标

 为什么要用   requestAnimationFrame  ,jQuery1.6.2还用 requestAnimationFrame,之后便放弃了。

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

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

  

如下 jquery:

// 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 放弃,上面说的比较完善;

 

 

 

;(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;
	}
}






var now=function (){
	return +new Date();
}


function startMove(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 = now();
	
	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|| window.pageYOffset|| document.documentElement.scrollTop;		 
			}
		else{
			iCur[attr] = parseInt(getStyle(obj,attr)) || 0;
		}
		
	}
	
	
	    if(obj.timer){
		cancelAnimationFrame(obj.timer)
		}
		//obj.timer=null;
	
	function update(){	
		
		var changeTime = now();
		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.call(obj);
				console.log(‘222222222222‘);
		}else{
			 //setup_fps_meters();
			
			obj.timer=requestAnimationFrame(arguments.callee);
			}
		
   }//update  end
   //	requestAnimationFrame(update);  //某些时候 画的过快  有bug
	update();
	
}	

  

 

 另外比较强大的 动画库 推荐

 snabbt.js

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

 

 

移动端 动画函数 的 封装

标签:

原文地址:http://www.cnblogs.com/surfaces/p/5129868.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!