声明:此程序仅针对手机端,简单的封装一个插件,意在记载插件的开发过程,如有错误及不足之处,还望即时指出.
移动开发的时候,我们经常会遇到滑动事件,众所周知主要依靠 touch 事件.最近接连遇到两个页面都有类似 overflow:auto 的效果,一般情况下通过 CSS 设置是可以实现的(虽说丑了点儿),,但是一旦 overflow:auto 的元素响应 touch 事件时就会有诸多不便,例如 fullpage 中某一元素自滑动,我们可以通过 normalScrollElements 来使元素滑动的时候不滑动到下一屏,但是在元素滑动到最底部的时候也就不能响应下一屏事件,上滑也是一样,这时候就需要 touch 事件来响应,为了以后封装方便,特简单封装一个 jquery 插件,同时也复习一下 jquery 插件开发及 touch 事件;
插件大体思路是这样的,如下图所示:方框内区域为固定宽高的父元素(设置 overflow:hidden),子元素高度大于父元素,我们通过响应 touch 事件改变子元素的 translate 值(top 也可以,但是 translate 效率更高一些),当然在此期间我们需判断子元素 translate 值的边界,最大为 0,最小为子元素高度 - 父元素高度
ps:如果想做子元素根据手指移动,松开手指后回到边界需另写程序
下面来一步步写插件
第一步,先建立一个安全的作用域
; (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
})
来源: http://www.cnblogs.com/mopagunda/p/5761719.html