一、移动端touch事件
(1)主要事件:
移动端的touch事件(触屏事件)是针对移动web开发的,PC端不支持。它有以下三个主要事件:
touchstart | 手指触摸屏幕时触发 |
touchmove | 手指在屏幕上移动时持续触发 |
touchend | 手指离开屏幕时触发 |
(2)touchEvent:
touchEvent(事件元参数)重点关注以下对象:
touches | 位于屏幕上的所有手指触摸点列表,是一个数组 |
targetTouches | 位于当前元素上的所有手指的列表,是一个数组(常用) |
changedTouches | 当前屏幕上变换的手指对象——从无到有,从有到无,即touchstart 时包含刚与屏幕接触的对象,touchend 时包含离开触摸屏的对象 |
target | 获取当前触摸的元素 |
(3)重要属性:
clientX/Y | 手指的触摸点相对于当前视口的坐标距离 |
pageX/Y | 手指的触摸点相对于页面内容的坐标距离(含滚动) |
screenX/Y | 手指的触摸点相对于屏幕左上角的坐标距离 |
二、移动端click事件
在PC端,我们用click事件来实现点击。实际上,移动端也是支持click事件的,但是click事件在移动端会有延时(不同设备延迟不同,我们经常说是延时300ms),即从点击屏幕上的元素到触发元素的click事件,移动浏览器会有大约 300 毫秒的等待时间。因为移动浏览器想要看看用户是否会进行双击操作(double tap)。
我们可以简单验证一下,验证思路是为一个DOM元素先后添加多个事件——mousedown、click、mouseup、touchstart、touchend。查看打印结果的先后顺序及时间差:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<style>
body{
padding: 0;
margin: 0;
text-align: center;
background-color: aliceblue;
}
.result{
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
margin: 100px auto 0;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="result">
给我点下去
</div>
<script>
var startTime;
//打印信息函数
var printMessage = function(name){
//创建DOM节点,显示信息
var div = document.createElement("div");
//计算触发时间
// new Date().getTime():获取当前时间
div.innerHTML = (new Date().getTime()) + ":" + (new Date().getTime() - startTime) + ":" + name;
//添加到页面中
document.body.appendChild(div);
};
// 触屏开始
var touchStart = function(){
startTime = new Date().getTime();
printMessage("touchStart");
};
// 触屏结束
var touchEnd = function(){
printMessage("touchEnd");
};
// 鼠标按下
var mouseDown = function(){
printMessage("mouseDown");
};
// 鼠标点击
var mouseClick = function(){
printMessage("mouseClick");
};
// 鼠标抬起
var mouseUp = function(){
printMessage("mouseUp");
};
// 添加事件元素
var result = document.querySelector('.result');
// 分别绑订事件
result.addEventListener('mousedown', mouseDown);
result.addEventListener('click', mouseClick);
result.addEventListener('mouseup', mouseUp);
result.addEventListener('touchstart', touchStart);
result.addEventListener('touchend', touchEnd);
</script>
</body>
</html>
实现结果:
可以看出,虽然在代码中mouse事件写在touch事件之前,但是浏览器实际上是先触发touch事件,再触发mouse事件。并且这里的延时大概是100ms。
三、移动端tap事件
我们在移动设备单击时,往往不是touch那么简单,比如它需要区分于“长按”和“单击”。移动端的单击(tap)有如下需求:
* 1.单击只有一根手指
* 2.判断手指开始触摸和手指松开的时间差异不能大于指定的值(若大于指定的值则视为长按操作)
* 3.保证没有滑动操作,但可以有些微的抖动,即抖动的距离在指定范围内(超出范围则视为滑动操作)
(1)touch事件来模拟移动端tap:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Title</title>
<style>
div{
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div></div>
<script>
/*单击操作的特点
* 1.单击只有一根手指
* 2.判断手指开始触摸和手指松开的时间差异不能大于指定的值 300/150
* 3.保证没有滑动操作,如果有抖动必须保证抖动的距离在指定范围内*/
var div=document.querySelector("div");
var startTime,startX,startY;
div.addEventListener("touchstart",function(e){
/*判断是否只有一根手指进行操作*/
if(e.targetTouches.length > 1){ //说明不止一个手指
return;
}
/*记录手指开始触摸的时间*/
startTime=Date.now();
/*记录当前手指的坐标*/
startX= e.targetTouches[0].clientX;
startY= e.targetTouches[0].clientY;
/*来做一些与事件相关的初始化操作*/
})
/*touchend:当手指松开时候触发,意味着当前元素上已经没有手指对象了,所以无法通过targetTouches来获取手指对象*/
div.addEventListener("touchend",function(e){
/*判断是否只有一根手指进行操作*/
if(e.changedTouches.length > 1){ //说明不止一个手指
return;
}
/*判断时间差异 150ms*/
console.log(Date.now()-startTime);
if(Date.now()-startTime > 150){ //长按操作
return;
}
/*判断松开手指时的坐标与触摸开始时的坐标的距离差异*/
var endX=e.changedTouches[0].clientX;
var endY=e.changedTouches[0].clientY;
/*这里暂且将距离差异定为6*/
if(Math.abs(endX-startX) < 6 && Math.abs(endY-startY) <6){
console.log("这就是移动端的单击事件--tap事件");
/*执行tap事件响应后的处理操作*/
}
})
</script>
</body>
</html>
(2)tap事件封装:
将上面的tap事件代码封装为一个函数tap,存储在对象itcast中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Title</title>
<style>
div{
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div></div>
<script>
var itcast = {
tap:function(dom,callback){
/*单击操作的特点
* 1.单击只有一根手指
* 2.判断手指开始触摸和手指松开的时间差异不能大于指定的值 300/150
* 3.保证没有滑动操作,如果有抖动必须保证抖动的距离在指定范围内*/
var startTime,startX,startY;
dom.addEventListener("touchstart",function(e){
/*判断是否只有一根手指进行操作*/
if(e.targetTouches.length > 1){ //说明不止一个手指
return;
}
/*记录手指开始触摸的时间*/
startTime=Date.now();
/*记录当前手指的坐标*/
startX= e.targetTouches[0].clientX;
startY= e.targetTouches[0].clientY;
/*来做一些与事件相关的初始化操作*/
})
/*touchend:当手指松开时候触发,意味着当前元素上已经没有手指对象了,所以无法通过targetTouches来获取手指对象*/
dom.addEventListener("touchend",function(e){
/*判断是否只有一根手指进行操作*/
if(e.changedTouches.length > 1){ //说明不止一个手指
return;
}
/*判断时间差异 150ms*/
console.log(Date.now()-startTime);
if(Date.now()-startTime > 150){ //长按操作
return;
}
/*判断松开手指时的坐标与触摸开始时的坐标的距离差异*/
var endX=e.changedTouches[0].clientX;
var endY=e.changedTouches[0].clientY;
/*这里暂且将距离差异定为6*/
if(Math.abs(endX-startX) < 6 && Math.abs(endY-startY) <6){
console.log("这就是移动端的单击事件--tap事件");
/*执行tap事件响应后的处理操作*/
callback && callback(e);
}
})
}
}
var div = document.querySelector("div");
itcast.tap(div,function(){
alert("这就是移动端的单击事件--tap事件");
});
</script>
</body>
</html>
(3)zepto的tap事件
zepto中已经封装好了tap事件,使用起来非常方便:
<script src="zepto-master/dist/zepto.js"></script>
<script>
$("div").on("tap",function(){
alert("这就是zepto中的tap!");
});
</script>
四、tap事件的点透
在移动设备上为了提升click的响应速度,我们选择了使用Zepto事件封装的tap来进行模拟,但是这会带来一个副作用,这个副作用就是“点透”,所谓点透指的就是当两个元素A(添加了click事件)、B(添加了tap事件)覆盖在一起时(见下图),当我们点击B,触发了B的tap事件的同时,也会触发A的click事件,这就是点透。
五、fastclick
优点:
(1)fastclick可以解决点透问题(Zepto也能解决点透问题,但是并不完善);
(2)不仅能在移动端被触发,也可以在PC端被触发(touch事件只能在移动端被触发);
(3)响应速度提升;
使用方法:
(1)引入fastclick.js文件:
<script src="./js/fastclick.js"></script>
(2)为DOM元素绑定fastclick:
fastclick.js主要是为指定的DOM元素绑定fastclick,绑定了fastclick的DOM元素的click事件已经不是原生的click事件,而是经过封装的click事件。
为DOM元素绑定fastclick:FastClick.attach(document.body);
其中参数可以是任意的dom元素,如果写document.body,说明会将document.body下面的所的元素都绑定fastclick
(3)原生JavaScript使用:
<script>
document.addEventListener('DOMContentLoaded', function() {
/*参数可以是任意的dom元素,如果写document.body,说明会将document.body下面的所的元素都绑定fastclick*/
FastClick.attach(document.body);
}, false);
tap.addEventListener("click",function(){
tap.style.visibility="hidden";
})
click.addEventListener("click",function(){
console.log(123);
})
</script>
(4)Zepto使用:
<script>
$(function() {
FastClick.attach(document.body);
});
var tap = $(".tap");
var click = $(".click");
tap.on("click",function(){
tap.css("visibility","hidden");
});
click.on("click",function(){
console.log(123);
});
</script>