移动端 动画函数 的 封装

移动端 单页有时候 制作只用到简单的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

				
时间: 2024-11-03 22:15:58

移动端 动画函数 的 封装的相关文章

JavaScript——WEBAPIS_深入动画函数的封装,常见网页特效

深入动画函数的封装 1.动画函数的封装 1.1 缓动效果的实现 这里有一些核心的算法,(目标值 - 现在的位置) ??/??10 = 每一次移动的步长 拿一个具体的效果举例子,比如让一个元素慢下来, 实现想法:让元素的移动距离变下,每一次的步长都变小,核心的算法:** (目标值 - 现在的位置) ??/??10??? 做为每次移动的距离步长**,其停止的条件就是当盒子到达目标位置就停止定时器 实现的代码: <body> <button>点击之后老李才飞!</button>

js-特效部分学习-offsetParent、scrollHeight 、动画函数的封装

1. offsetParent  获取的最近的定位的父元素   offsetLeft/offsetTop  是相对于offsetParent的距离 offsetHeight/offsetWidth 获取盒子的大小   border + height + padding <style> #box { width: 200px; height: 200px; background-color: #ff0000; } #child { width: 100px; height: 100px; mar

原生JS实现动画函数的封装

封装了一个JS方法,支持元素的基本动画:宽.高.透明度...等,也支持链式动画和同时运动. 获取元素的属性的函数并进行了兼容性处理: 1 function getStyle(obj, attr) { 2 if(obj.currentStyle){ //IE浏览器 3 return obj.currentStyle[attr]; 4 }else{ //chrome.firefox等浏览器 5 return getComputedStyle(obj,null)[attr]; 6 } 7 } 动画函数

移动端滑屏全应用【四】移动端动画贞动画函数mTween封装

首先此函数是基于大家都知道的Tween动画算法的,在此基础上使用了三中讲到的兼容版动画贞,可以使动画变得更流畅. 1. 首先要记得引入Tween.js 2. 引入mTween.js 3. 调用 * mTwee.js文件如下: (这里的m意为mobile) (function(){ window.requestAnimationFrame = window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRe

基础 - 动画函数的封装

小数的取整 WHY? JS对于小数的处理能力有限 Math.round() 四舍五入取整 Math.ceil() 向上取整 Math.floor() 向下取整 属性的访问 点语法 [""]法 得到内嵌和外链的CSS 兼容写法

移动端滑屏全应用【一】cssHandler操作基础动画函数封装

前言: 大家都知道,在移动端进行操作结点移动时,我们都会使用操作transform来代替top等用以提高性能,必要的时候还可开启3d加速.我们都会使用getComputedStyle来获取结点的最终样式,但使用getComputedStyle来获取transform时我们获取到的是一个矩阵值,而且是无法通过设置矩阵值反向设置transform的效果的.如下: body.style.WebkitTransform = 'translateY(50px)' getComputedStyle(body

变速动画函数封装增加任意一个属性

//计算后的样式属性---- 一个元素的任意的一个样式属性值function getStyle(element,attr) { //判断这个浏览器是否支持这个方法 return window.getComputedStyle?window.getComputedStyle(element,null)[attr]:element.currentStyle[attr];}//匀速动画function animate(element,attr,target) { //element--元素 attr-

通过轮播图例子复习封装动画函数和定时器

概述:使用js实现自动播放.无缝连接的轮播图 图片轮播的实质是改变图片相对于父对象的左边距的值,利用offsetLeft获取,利用style.left修改 封装动画函数如下: function animate(element,target) { clearInterval(element.timeId); element.timeId=setInterval(function(){ var current=element.offsetLeft; var step=10; step=target>

JavaScript—封装animte动画函数

封装Animte 动画函数 虽然可能以后的开发中可能根本不需要自己写,Jquery 给我们封装好了,或者用CSS3的一些属性达到这样的效果可能更简单. 我比较喜欢底层的算法实现,万变不离其中,这个逻辑思路,也是需要锻炼的.也跟着做了一遍 ///动画函数 //element:元素 //target:最后停止的位置 function animte(element, target) { //只有一个Timeid定时器在执行 if (element,timerId) { clearInterval(el