移动前端学习笔记(2)——移动端点击(touch、click、tap、fastclick)

本文介绍了移动前端中常见的点击事件,包括touch事件、click事件的300ms延迟问题、tap事件的实现与需求,以及解决点透问题的fastclick库。通过实例展示了zepto的tap事件封装和fastclick的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、移动端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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值