前端----谈谈移动端点击事件

浅谈移动端的click事件被tap事件代替的原因

1. 移动端点击事件click出现延迟

工作中接触了移动端,发现同事们都会用如下代码去写移动端的点击事件,尝试使用,屡试不爽,一旦没有用下边这段代码,点击事件就会出现各种各样的问题,在连续使用了N多次之后(本人并没有爱钻研的精神~~有点儿懒),终于决定自己上网查一些资料,看看到底是什么原因呗。(解释jquery的方法data():在匹配元素上存储任意相关数据 或 返回匹配的元素集合中的第一个元素的给定名称的数据存储的值。trigger():规定被选元素要触发的事件。)

//自定义tap
$(document).on("touchstart", function(e) {
    if(!$(e.target).hasClass("disable")) $(e.target).data("isMoved", 0);
});
$(document).on("touchmove", function(e) {
    if(!$(e.target).hasClass("disable")) $(e.target).data("isMoved", 1);
});
$(document).on("touchend", function(e) {
    if(!$(e.target).hasClass("disable") && $(e.target).data("isMoved") == 0) $(e.target).trigger("tap");
});

2. 问题出在哪了

为什么要用tap事件代替click事件?答案:300 毫秒延迟

这要追溯至 2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题 —— 当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕访问电脑版的网页的问题。这当中最出名的,当属双击缩放(double tap to zoom)。

当用户一次点击屏幕之后,浏览器并不能立刻判断用户是要进行双击缩放,还是想要进行单击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。

于是,300 毫秒延迟就这么诞生了。

鉴于iPhone的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎现在所有的移动端浏览器都有这个功能(嗯~尝试了一下好像微信浏览器没有再遵守这个双击缩放的约定)。之前人们刚刚接触移动端的页面,在欣喜的时候往往不会care这个300ms的延时问题,可是如今移动端界面如雨后春笋,用户对体验的要求也更高,这300ms带来的卡顿慢慢变得让人难以接受。

3. 实例操作300ms出现的过程

一开始触摸事件touchstart、touchmove和touchend是iOS版Safari浏览器为了向开发人员传达一些信息新添加的事件。因为iOs设备既没有鼠标也没有键盘,所以在为移动Safari浏览器开发交互性网页的时候,PC端的鼠标和键盘事件是不够用的。

在iPhone 3Gs发布的时候,其自带的移动Safari浏览器就提供了一些与触摸(touch)操作相关的新事件。随后,Android上的浏览器也实现了相同的事件(大家统一了,移动端浏览器都有了touch事件啦)。触摸事件(touch)会在用户手指放在屏幕上面的时候、在屏幕上滑动的时候或者是从屏幕上移开的时候触发。下面具体说明:

  touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。

  touchmove事件:当手指在屏幕上滑动的时候连续地触发。这个事件发生期间,调用preventDefault()事件可以阻止滚动。

  touchend事件:当手指从屏幕上离开的时候触发。

  touchcancel事件:当系统停止跟踪触摸的时候触发。关于这个事件的确切时间,文档中并没有具体说明,这里不再详述。

touch事件及click事件同时绑定在一个元素上demo:(一言不合上代码~~e.type指代事件类型)

	$(document).on('touchstart', '.wantUp', function(e) {
		$(".upArtical1 h5.up").append(e.type);
	})
	$(document).on('touchmove', '.wantUp', function(e) {
		$(".upArtical1 h5.up").append(e.type);
	})
	$(document).on('touchend', '.wantUp', function(e) {
		$(".upArtical1 h5.up").append(e.type);
	})
	$(document).on('click', '.wantUp', function(e) {
		$(".upArtical1 h5.up").append(e.type);
	});

可以看到,我在一个元素上边绑定了 touchstart , touchmove , touchend ,click事件,奇妙的事情发生了:

  • touch, click事件的执行顺序: touchstart > touchmove > touchend > click。很明显,touch事件执行完毕后才会到click事件,这就是我们所说的300ms的延迟。
  • touchmove ,click事件互斥,即touchmove触发执行,click事件不再执行 ,事件的执行顺序就为touchstart > touchmove(可以多次执行) > touchend 。
  • 短暂触摸(点)一下屏幕,上述代码的事件的执行顺序:touchstart > touchend > click。

OK,到目前为止我们已经阐述了300ms的产生,而这300ms的产生还带来一个巨大的问题,点透事件。

4. 点透事件

点透发生的条件:

  •  A 和 B不是后代继承关系(如果是后代继承关系的话,就直接是冒泡之类的话题了(在此不再赘述 ))
  •  A发生touch(也可以是click)后立即消失,B事件绑定click   
  •  A z-index大于B,即A显示在B浮层之上

 点透发生的原因:  

       当手指触摸到屏幕的时候,系统生成两个事件,一个是touch 一个是click,touch先执行,touch执行完成后,A从文档树上面消失了,而且由于移动端click还有延迟200-300ms的关系,当系统要触发click的时候,发现在用户点击的位置上面,目前离用户最近的元素是B,所以就直接把click事件作用在B元素上面了

 A.addEventListener('touch', function(e) {
    A.style.display = 'none';
 });
 A.onclick = function() {
    console.log('B莫名被点击了');
 }    

解决方案是touch阶段取消掉 click 事件:touch事件内调用:e.preventDefault()   

5. 解决方案

以上问题的解决方案就是:既然浏览器统一了touch事件,就用touch事件去模拟click事件。

还记得文章最开始的那段代码吗?

//自定义tap
$(document).on("touchstart", function(e) {
    if(!$(e.target).hasClass("disable")) $(e.target).data("isMoved", 0);
});
$(document).on("touchmove", function(e) {
    if(!$(e.target).hasClass("disable")) $(e.target).data("isMoved", 1);
});
$(document).on("touchend", function(e) {
    if(!$(e.target).hasClass("disable") && $(e.target).data("isMoved") == 0) $(e.target).trigger("tap");
});

解释一下吧:现在原理就很明显了~

基于touchstart、touchmove、touchend这三个事件,通过事件委托的方式来实现tap事件。

e.target是事件源的触发节点,$(e.target)是该节点的jQuery封装对象,isMoved这个就相当于一个开关,移动了置为1,没移动置为0。

第一步:监听touchstart事件,事件触发后通过jQuery的data方法设置该对象的isMoved状态为0。

第二步:监听touchmove事件,事件触发后通过jQuery的data方法设置该对象的isMoved状态为1。

第三步:监听touchend事件,事件触发后判断该对象是否touchMove过,没有则触发tap事件。

如何算tap事件:手指点上去 不移动 快速松开 。

6. 如何使用这段代码?

  • 复制上述代码到页面js处
  • 对该使用click事件的元素统一换成tap事件

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值