触摸事件
touch是一个事件组,意思不止一个事件,是移动端滑动事件组,touchstart touchmove touchend touchcancel
touchstart 当刚刚触摸屏幕的时候触发
touchmove 在屏幕上来回的滑动的时候触发
touchend 离开屏幕的时候触发
touchcancel *终止触摸的时候触发 (例如:来电 消息弹窗)
<div class="box"></div>
<script>
var box = document.querySelector('.box');
/*1 touchstart 当刚刚触摸屏幕的时候触发 */
box.addEventListener('touchstart', function (e) {
console.log('touchstart');
console.log(e);
});
/*2 touchmove 在屏幕上来回的滑动的时候触发*/
box.addEventListener('touchmove', function (e) {
console.log('touchmove');
});
/*3 touchend 离开屏幕的时候触发*/
box.addEventListener('touchend', function (e) {
console.log('touchend');
console.log(e);
}); /*获取触摸点坐标*/
/*1. clientX/Y 记录的是基于视口的坐标*/
/*2. pageX/Y 记录的是基于页面的坐标*/
/*3. screenX/Y 记录的是基于屏幕的坐标*/
/*不管什么坐标都可以 需要的是位置的改变 */
</script>
Tap事件
在移动端使用click
事件时,会存在大概200~300ms的延迟,如果不自己封装tap
事件,那么就需要引入fastclick.js
文件。
singleTap事件
tap
事件是依据touches
组来封装的:
自己封装的tap
事件:
var tap = function(dom,callback){
//判断是否滑动过
var isMove = false;
//记录响应的速度
var time = 0;
dom.addEventListener('touchstart',function(e){
time = Date.now();
console.log(e);
});
dom.addEventListener('touchmove',function(e){
isMove = true;
});
dom.addEventListener('touchend',function(e){
var respondTime = Date.now() - time;
/*tap*/
if(!isMove && respondTime < 150){
/*满足条件*/
callback && callback();
}
//重置
isMove = false;
});
} var box = document.querySelector('.box'); tap(box, function(){
// your code...
console.log('tap触发了');
});
HTMLElement.prototype.myTap = HTMLElement.prototype.myTap || function (callBack) {
// myTapStart --- touchstart事件时间戳
// myTapEnd --- 获取touchend事件时间戳
// timeTap --- myTapStart - myTapEnd <= timeTap 时,被认为触发 tap 事件
let myTapStart = 0,
myTapEnd = 0,
timeTap = 300;
// 监听 touchstart 事件
this.addEventListener('touchstart', function (e) {
// 获取touchstart事件的时间戳
myTapStart = e.timeStamp;
// changedTouchs 是事件对象 TouchEvent 上面的属性,上面存储了一个当前操作的信息。
let point = e.changedTouches[0];
this.strX = point.pageX;
this.strY = point.pageY;
// 锁死 touchmove 事件
this.isMove = false;
}, false);
// 监听 touchmove 事件
this.addEventListener('touchmove', function (e) {
let point = e.changedTouches[0];
let changeX = point.pageX - this.strX;
let changeY = point.pageY - this.strY;
if (Math.abs(changeX) > 10 || Math.abs(changeY) > 10) {
this.isMove = true;
}
}, false);
// 监听 touchend 事件
this.addEventListener('touchend', function (e) {
// 获取 touchend 事件的时间戳
myTapEnd = e.timeStamp;
const isTimeTap = myTapEnd - myTapStart;
if (!this.isMove && isTimeTap <= timeTap) {
callBack();
}
}, false);
}; let box = document.querySelector(".box"); box.myTap(function () {
// your code...
console.log("单击事件myTap");
});
doubleTap事件
HTMLElement.prototype.doubleTap = HTMLElement.prototype.doubleTap || function (callBack) {
// isTouchEnd
// lastTime
// lastTx lastTy --- 合理范围内的误差
// firstTouchEnd --- 第一次 触发 touchend 事件
// body --- iphone os
// dTapTimer --- 定时器
// startTx startTy --- 获取 touchstart 的位置
// startTime --- 兼容 iphone os
let isTouchEnd = false,
lastTime = 0,
lastTx = null,
lastTy = null,
firstTouchEnd = true,
body = document.body,
dTapTimer, startTx, startTy, startTime;
// 监听 touchstart
this.addEventListener('touchstart', function (e) {
// 清除定时器s
if (dTapTimer) {
console.log('dTapTimer');
clearTimeout(dTapTimer);
dTapTimer = null;
}
// 获取 touchstart 的位置
const touches = e.touches[0];
startTx = touches.clientX;
startTy = touches.clientY;
}, false); // 监听 touchend
this.addEventListener('touchend', function (e) {
const touches = e.changedTouches[0],
endTx = touches.clientX,
endTy = touches.clientY,
now = Date.now(),
duration = now - lastTime; // 首先要确保能触发单次的 tap 事件
if (Math.abs(startTx - endTx) < 6 && Math.abs(startTx - endTx) < 6) {
console.log('单次点击的 touchstart 的位置和 touchend 的位置允许 6px 的误差');
// 两次 tap 的间隔确保在 500 毫秒以内
if (duration < 501) {
// 本次的 tap 位置和上一次的 tap 的位置允许一定范围内的误差
if (lastTx !== null && Math.abs(lastTx - endTx) < 45 && lastTy !== null && Math.abs(lastTy - endTy) < 45) {
firstTouchEnd = true;
lastTx = lastTy = null;
callBack()
}
} else {
lastTx = endTx;
lastTy = endTy;
}
} else {
firstTouchEnd = true;
lastTx = lastTy = null;
}
// 获取上一次点击的时间戳
lastTime = now;
}, false); // 在 iOS 的 safari 上手指敲击屏幕的速度过快,
// 有一定的几率会导致第二次不会响应 touchstart 和 touchend 事件
// 同时手指长时间的touch不会触发click if (navigator.userAgent.toLowerCase().indexOf('iphone os')) {
console.log('iphone os');
body.addEventListener('touchstart', function (e) {
startTime = Date.now();
}, true); body.addEventListener('touchend', function (e) {
let noLongTap = Date.now() - startTime < 501;
if (firstTouchEnd) {
firstTouchEnd = false;
if (noLongTap && e.target === this) {
dTapTimer = setTimeout(function () {
// 永远不会执行setTimeout里面的代码,因为在 click 中清除了 dTapTimer
firstTouchEnd = true;
lastTx = lastTy = null;
console.log('fire double tap event at iphone os');
callBack()
}, 400);
}
} else {
firstTouchEnd = true;
}
}, true); // iOS 上手指多次敲击屏幕时的速度过快不会触发 click 事件
body.addEventListener('click', function (e) {
if (dTapTimer) {
clearTimeout(dTapTimer);
dTapTimer = null;
firstTouchEnd = true;
}
}, false); }
}
let box = document.querySelector('.box')
box.doubleTap(function() {
console.log('doubleTap 触发了')
})
longTap事件
<script>
HTMLElement.prototype.longTap = HTMLElement.prototype.longTap || function (callBack) {
let startTx, startTy, lTapTimer;
this.addEventListener('touchstart', function (e) {
// 清除定时器
if (lTapTimer) {
clearTimeout(lTapTimer);
lTapTimer = null;
}
// 获取 touchstart 位置
let touches = e.touches[0];
startTx = touches.clientX;
startTy = touches.clientY; lTapTimer = setTimeout(function () {
callBack()
console.log('fire long tap event');
}, 1000); e.preventDefault();
}, false); this.addEventListener('touchmove', function (e) {
// 获取 touchmove 位置
let touches = e.touches[0],
endTx = touches.clientX,
endTy = touches.clientY;
// 定时器存在 并且 发生了 touchmove 清除定时器
if (lTapTimer && (Math.abs(endTx - startTx) > 5 || Math.abs(endTy - startTy) > 5)) {
clearTimeout(lTapTimer);
lTapTimer = null;
}
}, false); this.addEventListener('touchend', function (e) {
if (lTapTimer) {
clearTimeout(lTapTimer);
lTapTimer = null;
}
}, false); } let box = document.querySelector('.box')
box.longTap(function() {
// your code ...
console.log('longTap 触发了')
})
swipe事件
HTMLElement.prototype.swipe = HTMLElement.prototype.swipe || function (callBack) {
let isTouchMove, startTx, startTy;
this.addEventListener('touchstart', function (e) {
let touches = e.touches[0]; startTx = touches.clientX;
startTy = touches.clientY;
isTouchMove = false;
}, false); this.addEventListener('touchmove', function (e) {
isTouchMove = true;
e.preventDefault();
}, false); this.addEventListener('touchend', function (e) {
if (!isTouchMove) {
return;
} let touches = e.changedTouches[0],
endTx = touches.clientX,
endTy = touches.clientY,
distanceX = startTx - endTx
distanceY = startTy - endTy,
isSwipe = false; if (Math.abs(distanceX) >= Math.abs(distanceY)) {
if (distanceX > 20) {
callBack('left')
console.log('fire swipe left event');
isSwipe = true;
} else if (distanceX < -20) {
callBack('right')
console.log('fire swipe right event');
isSwipe = true;
}
} else {
if (distanceY > 20) {
callBack('up')
console.log('fire swipe up event');
isSwipe = true;
} else if (distanceY < -20) {
callBack('down')
console.log('fire swipe down event');
isSwipe = true;
}
} if (isSwipe) {
console.log('fire swipe event');
}
}, false);
} let box = document.querySelector('.box')
box.swipe(function (direct) {
// your code ...
console.log('swipe 触发了' + direct)
})