移動H5開發中經常用到滑動效果(頁面上移、下移、向左滑動、向右滑動等),瀏覽器並沒有內置swipe事件,可以通過touch事件(touchstart、touchmove和touchend)模擬swipe效果。jquery mobile和zeptojs提供了swipe事件。jquery mobile只有swipeLeft和swipeRight,zeptojs提供了完整的tap和swipe事件。
/**
* @author [email protected]
* http://git.oschina.net/accountwcx/rhui
*
* swipe事件,包括swipeLeft、swipeRight、swipeUp、swipeDown。
* 調用方法
* Rhui.mobile.swipeLeft(el, callback, options)
* Rhui.mobile.swipeRight(el, callback, options)
* Rhui.mobile.swipeUp(el, callback, options)
* Rhui.mobile.swipeDown(el, callback, options)
* 如果使用jQuery,調用方法
* $(el).rhuiSwipe('swipeLeft', callback, options);
* $(el).rhuiSwipe('swipeRight', callback, options);
* $(el).rhuiSwipe('swipeUp', callback, options);
* $(el).rhuiSwipe('swipeDown', callback, options);
*/
(function(window, $){
var Rhui = window.Rhui || {};
window.Rhui = Rhui;
Rhui.mobile = (function(){
var touch = {
distance: 30, //滑動距離,超過該距離觸發swipe事件,單位像素。
duration: 1000 //滑動時長,超過該時間不觸發swipe,單位毫秒。
};
/**
* 綁定事件
* @param el 觸發事件的元素
* @param swipe 事件名稱,可選值爲swipeLeft,swipeRight,swipeUp,swipeDown
* @param callback 事件回調函數
* @param isStopPropagation 是否停止冒泡,true爲停止冒泡
* @param isPreventDefault 是否阻止默認事件,true爲阻止默認事件
* @param triggerOnMove swipe事件有兩種觸發方式,一種是在touchmove過程中,只要滿足滑動距離條件即觸發。
* 一種是在touchend中,進入滑動距離判斷,如果滿足滑動距離觸發。
* 默認是在touchend中觸發。
*/
function bindSwipe(el, swipe, callback, triggerOnMove, isStopPropagation, isPreventDefault){
var startPoint, endPoint, timer;
/**
* 計算滑動方向
* 首先根據x方向和y方向滑動的長度決定觸發x方向還是y方向的事件。
* 然後再判斷具體的滑動方向。
* 如果滑動距離不夠長,不判斷方向。
*/
function swipeDirection(x1, y1, x2, y2){
var diffX = x1 - x2,
diffY = y1 - y2,
absX = Math.abs(diffX),
absY = Math.abs(diffY),
swipe;
if(absX >= absY){
if(absX >= touch.distance){
swipe = diffX > 0 ? 'swipeLeft' : 'swipeRight';
}
}else{
if(absY >= touch.distance){
swipe = diffY > 0 ? 'swipeUp' : 'swipeDown';
}
}
return swipe;
}
// 清除本次滑動數據
function clearSwipe(){
startPoint = undefined;
endPoint = undefined;
if(timer !== undefined){
clearTimeout(timer);
timer = undefined;
}
}
/**
* 判斷是否符合條件,如果符合條件就執行swipe事件
* @param el {HTMLElement} 元素
* @param event {Event} Touch原始事件
* @param return 如果執行了事件,就返回true。
*/
function execSwipe(el, event){
if(startPoint && endPoint && swipeDirection(startPoint.x, startPoint.y, endPoint.x, endPoint.y) === swipe){
callback.call(el, event);
return true;
}
}
el.addEventListener('touchstart', function(event){
var self = this, touchPoint = event.touches[0];
if(isStopPropagation){
event.stopPropagation();
}
if(isPreventDefault){
event.preventDefault();
}
startPoint = {
x: Math.floor(touchPoint.clientX),
y: Math.floor(touchPoint.clientY)
};
timer = setTimeout(function(){
//如果超時,清空本次touch數據
clearSwipe();
}, touch.duration);
});
el.addEventListener('touchmove', function(event){
var self = this, touchPoint = event.touches[0];
if(isStopPropagation){
event.stopPropagation();
}
if(isPreventDefault){
event.preventDefault();
}
if(startPoint){
endPoint = {
x: Math.floor(touchPoint.clientX),
y: Math.floor(touchPoint.clientY)
};
//執行swipe事件判斷,是否符合觸發事件
if(triggerOnMove){
if(execSwipe(self, event)){
clearSwipe();
}
}
}
});
el.addEventListener('touchend', function(event){
if(isStopPropagation){
event.stopPropagation();
}
if(isPreventDefault){
event.preventDefault();
}
execSwipe(self, event);
//清除本次touch數據
clearSwipe();
});
}
/**
* @param el {HTMLElement} HTML元素
* @param callback {Function} 事件回調函數
* @param options {Object} 可選參數
* isStopPropagation {Boolean} 是否停止冒泡,true爲停止冒泡
* isPreventDefault {Boolean} 是否阻止默認事件,true爲阻止默認事件
* triggerOnMove {Boolean}
* swipe事件有兩種觸發方式,一種是在touchmove過程中,只要滿足滑動距離條件即觸發。
* 一種是在touchend中,進入滑動距離判斷,如果滿足滑動距離觸發。
* 默認值爲false,在touchend中觸發。
*/
touch.swipeLeft = function(el, callback, options){
if(options){
bindSwipe(el, 'swipeLeft', callback, options.triggerOnMove, options.isStopPropagation, options.isPreventDefault);
}else{
bindSwipe(el, 'swipeLeft', callback);
}
};
touch.swipeRight = function(el, callback, options){
if(options){
bindSwipe(el, 'swipeRight', callback, options.triggerOnMove, options.isStopPropagation, options.isPreventDefault);
}else{
bindSwipe(el, 'swipeRight', callback);
}
};
touch.swipeUp = function(el, callback, options){
if(options){
bindSwipe(el, 'swipeUp', callback, options.triggerOnMove, options.isStopPropagation, options.isPreventDefault);
}else{
bindSwipe(el, 'swipeUp', callback);
}
};
touch.swipeDown = function(el, callback, options){
if(options){
bindSwipe(el, 'swipeDown', callback, options.triggerOnMove, options.isStopPropagation, options.isPreventDefault);
}else{
bindSwipe(el, 'swipeDown', callback);
}
};
return touch;
})();
// 註冊jquery方法
if($ && $.fn){
$.fn.extend({
/**
* 模擬touch swipe事件,支持鏈式調用。
* @param name {String} swipe事件名稱,值有swipLeft、swipeRight、swipeUp、swipeDown。
* @param callback {Function} swipe事件回調函數
* @param opts {Object} 可選參數
* isStopPropagation {Boolean} 是否停止冒泡,true爲停止冒泡
* isPreventDefault {Boolean} 是否阻止默認事件,true爲阻止默認事件
* triggerOnMove {Boolean} swipe事件有兩種觸發方式,一種是在touchmove過程中,只要滿足滑動距離條件即觸發。
* 一種是在touchend中,進入滑動距離判斷,如果滿足滑動距離觸發。
* 默認值爲false,在touchend中觸發。
*/
rhuiSwipe: function(name, callback, opts){
var fnSwipe = Rhui.mobile[name];
if(this.length > 0 && fnSwipe){
this.each(function(){
fnSwipe(this, callback, opts);
});
}
return this;
}
});
}
})(window, $);
使用實例
<style type="text/css">
.test{
width: 400px;
height: 400px;
}
</style>
<div id="div1" class="test"></div>
<div class="test"></div>
<script type="text/javascript">
Rhui.mobile.swipeUp(document.getElementById('div1'), function(event){
console.log(event);
}, {
// 可選參數
isStopPropagation: true,
isPreventDefault: true,
triggerOnMove: true
});
$('.test').rhuiSwipe('swipeLeft', function(event){
console.log(event);
}, {
// 可選參數
isStopPropagation: true,
isPreventDefault: true,
triggerOnMove: true
});
</script>
zeptojs touch事件
zeptojs也提供了滑動事件,該滑動事件需要引用額外的touch.js。
事件 | 描述 |
---|---|
tap | 類似PC端瀏覽器的鼠標點擊事件,由於移動瀏覽器點擊事件有延遲,tap提供了無延遲的點擊效果。 |
singleTap | 效果和tap一樣 |
doubleTap | 類似PC端瀏覽器的鼠標雙擊事件 |
longTap | 長按事件,在元素上長按超過0.75秒觸發。有些瀏覽器有默認的長按事件,可能會被覆蓋。 |
swipe | 滑動事件,該事件不考慮滑動方向。 |
swipeLeft | 向左滑動 |
swipeRight | 向右滑動 |
swipeUp | 向上滑動 |
swipeDown | 向下滑動 |
<style>.delete { display: none; }</style>
<ul id=items>
<li>List item 1 <span class=delete>DELETE</span></li>
<li>List item 2 <span class=delete>DELETE</span></li>
</ul>
<script>
// show delete buttons on swipe
$('#items li').swipe(function(){
$('.delete').hide()
$('.delete', this).show()
})
// delete row on tapping delete button
$('.delete').tap(function(){
$(this).parent('li').remove()
})
</script>