你的位置:首页 > Java教程

[Java教程]js+css3模拟溢出滚动


声明:此程序仅针对手机端,简单的封装一个插件,意在记载插件的开发过程,如有错误及不足之处,还望即时指出。

        

        移动开发的时候,我们经常会遇到滑动事件,众所周知手机端滑动主要依靠touch事件。最近接连遇到两个页面都有类似overflow:auto的效果,一般情况下通过css设置是可以实现的(虽说丑了点儿),,但是一旦overflow:auto的元素响应touch事件时就会有诸多不便,例如fullpage中某一元素自滑动,我们可以通过normalScrollElements来使元素滑动的时候不滑动到下一屏,但是在元素滑动到最底部的时候也就不能响应下一屏事件,上滑也是一样,这时候就需要touch事件来响应,为了以后封装方便,特简单封装一个jquery插件,同时也复习一下jquery插件开发及touch事件;

          插件大体思路是这样的,如下图所示:方框内区域为固定宽高的父元素(设置overflow:hidden),子元素高度大于父元素,我们通过响应touch事件改变子元素的translate值(top也可以,但是translate效率更高一些),当然在此期间我们需判断子元素translate值的边界,最大为0,最小为子元素高度-父元素高度 

         ps:如果想做子元素根据手指移动,松开手指后回到边界需另写程序

image      下面来一步步写插件

     第一步,先建立一个安全的作用域

;(function($){//插入代码})(jQuery)

 

     如果我们需要通过$(“#id”).xx()方法调用,需要像下面这样写,这里的fn及jquery的prototype;

      $.extend({

            exec:function(){}

      })    //这种扩展通过$.exec()调用

$.fn.simuScroll = function(option){    var scrollObj=new simuScroll(this,option);    return scrollObj.init();}

   

   下面来看上面代码中的simuScroll方法,这是一个构造函数,它接受两个参数,ele为当前接受touch事件的元素(一般可以设置为父元素),option为用户传入的配置参数,如改变translate的元素,父元素子元素高度,extra为需额外增加的高度,滑动到顶部或底部时执行的回调函数等等;

var simuScroll = function(ele,option){  this.settings = {     target : ele,  //事件元素     changeTarget:'',     outerHeight : '800',  //外层高度     innerHeight : '500',  //内层高度     extra : '0',      //额外增加的距离     swipeUp : null,     swipeDown : null,     vertical:true  };  //通过jquery.extend对默认的settings进行扩展,得出一个全新的对象  this.opt = jQuery.extend({},this.settings,option);      this.initNumber = this.lastNumber = this.result = 0;  this.flag = false;  //计算出子元素与父元素距离差,以此来判定元素的最大滑动距离  this.diff = parseFloat(this.opt.innerHeight) - parseFloat(this.opt.outerHeight) + parseFloat(this.opt.extra);  this.diff = this.diff < 0 ? 0 :this.diff;  this.direction = '';};

    

     在对jquery prototype进行扩展时,第一步为实例化上面的构造函数,第二步则直接调用了构造函数的init方法,具体见下面备注

init:function(){      //jquery对象直接绑定touch事件获取event需originalEvent获取原生对象的event属性      //jquery对象 获取pagex  event.originalEvent.touches[0].pageX        //dom对象 event.touches[0].pageX       var target = this.opt.target.get(0);             //如果子元素高度大于父元素,则执行滑动事件,否则执行回调函数      this.flag = this.diff > 0 ? 'translate' : 'exec';            /*如果元素已设置transform中 translate,scale,skew,rotate中的任何一项,       则我们再直接设置transform:translateY(10px)时会覆盖掉初始设置的属性       所以我们通过获取元素的matrix值既保证原有属性,又能设置任意值*/      var cssText = this.opt.changeTarget.css('-webkit-transform');      if(cssText=='none'){ //元素未设置transform属性        this.str = this.opt.vertical ? 'translateY' : 'translateX' ;      }else{        this.str = cssText ;        var reg = /-?\d+\.?\d*/g; //正则表达式                /*获取matrix中各参数         直接获取到的matrix值为类似matrix(1,0,0,1,0,0)         获取到的为[1,0,0,1,0,0] 这样我们就可以随意的修改某一个值         数组的第5项为元素的translateX值,第6项为translateY值 */        this.params = this.str.match(reg);         this.matrix = this.opt.vertical ? 6 : 5 ; //根据传入的参数确定要修改的值为translateY或tranlateX      }            var _this = this;            //父元素绑定touch事件,传递事件对象及context      target.addEventListener('touchstart',function(e){        _this.start(e,_this)      });      target.addEventListener('touchmove',function(e){        _this.move(e,_this)      });      target.addEventListener('touchend',function(e){        _this.end(e,_this)      });    }

     

touchstart方法相对比较简单,根据需要滑动的方向记录手指接触屏幕时的初始值

start:function(e,context){  e.preventDefault();  var touches = e.touches[0];  context.initNumber = context.opt.vertical ? touches.pageY : touches.pageX;},

  

touchmove方法主要根据手指滑动距离动态改变元素css属性,让元素能够跟随手指进行移动

setNumber方法只有一句话:  this.params.splice(n-1,1,number)  根据传入的参数改变matrix数组

move:function(e,context){  e.preventDefault();  var touches = e.touches[0];  number = context.opt.vertical ? touches.pageY : touches.pageX;    //获取相对手指触碰屏幕的变化值  var delta = number - context.initNumber;  if(context.flag == 'translate'){  //如果需要滑动    context.result = context.lastNumber + delta;        //设置滑动的最大值和最小值    context.result = context.result > 0 ? 0 : context.result ;    context.result = -context.result > context.diff ? -context.diff : context.result;        //动态设置元素css属性    if(context.matrix){      switch (context.matrix) {        case 6:           context.setNumber(6,context.result)           break;        case 5:           context.setNumber(5,context.result)           break;      }      context.opt.changeTarget.css('-webkit-transform','matrix('+context.params.join(',')+')')    }else{      context.opt.changeTarget.css('-webkit-transform',context.str+'('+context.result+'px)')    }  }},

 

touchend则判断释放时是否需要执行回调函数

end:function(e,context){  e.preventDefault();  var touches = e.changedTouches[0];  var number = context.opt.vertical ? touches.pageY : touches.pageX,    n = number - context.initNumber;      //当元素滑动距离大于10 并且最初元素translate值为0同时回调函数存在,则执行回调函数  if(n>10 && context.lastNumber == 0 && context.opt.swipeDown){     context.opt.swipeDown()  }else if(n<-10 && context.lastNumber == -context.diff && context.opt.swipeUp){    context.opt.swipeUp();  }    //将常量设为结果值,能保证多次连贯滑动  context.lastNumber = context.result;}

 

基本上一个简单的jQuery插件就完成了,框架如下

;(function($){  var a = function(m,n){    //函数内容  };    a.prototype = {    init:function(){          },    start:function(){          },    move:function(){          },    end:function(){          },    setNumber:function(){          }  }    $.fn.scrol = function(o){    var obj = new a(this,o);    return obj.init()  }  })(jQuery)

 

调用时如下:

$(".outer").simuScroll({  'outerHeight':$(".outer").height(),  'innerHeight':$('.inner').height(),  'changeTarget' : $(".inner"),  'swipeUp' :function(){    console.log('up')  },  'swipeDown' :function(){    console.log('down')  },  vertical:true})