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