web移动端触屏事件
1.移动端与pc端的区别
- (1)移动端没有鼠标,自然也没有鼠标事件。所以onmousedown之类的事件监听在移动端时无效的。
- (2)移动端为了响应双击事件,onclick事件有300ms的延迟,接下来的300ms内有没有再次点击,有的话视为双击,没有的话视为单击。
- (3)移动端双击事件:移动端双击时,除了有dblclick事件触发,还有相应的手势效果(放大/缩小),不过不同的浏览器效果不一致。有些浏览器两种特性都支持,有些只支持其中的一种,但是一般最少都支持一种。
下面的代码可以验证当前手机上onclick事件的延迟(在没有设置viewport的时候执行)
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<script>
var box = document.querySelector(".box")
var click_time,touchstart_time,touchend_time
box.ontouchstart = function(){
//获取事件触发时的时间戳
touchstart_time = new Date().getTime()
console.log('touchstart time = ' + touchstart_time)
}
box.ontouchend = function(){
//获取事件触发时的时间戳
touchend_time = new Date().getTime()
console.log('touchend time = ' + touchend_time)
}
box.onclick = function(){
//获取事件触发时的时间戳
click_time = new Date().getTime()
console.log('click time = ' + click_time)
//click一般要晚于touchend事件 我们来看看事件差
console.log(`与touchstart的时间差${click_time - touchstart_time}`)
console.log(`与touchend的时间差${click_time - touchend_time}`)
}
</script>
下面是chrome浏览器手机模式执行时的效果:
下面是火狐浏览器手机模式执行时的效果:
下面是Edge浏览器手机模式执行时的效果:
使用真机测试时记得引入下面的插件,才能查看控制台的输出情况:
<script src="http://cdn.jsdelivr.net/npm/eruda"></script>
<script>
eruda.init();
</script>
IOS13 Safari/chrome/edge/alook/执行效果都差不多,但是无论怎么算click延迟都大于300ms:
总结:click事件的延迟是存在的,但是不同的设备和浏览器计算延迟的方式不一致
下面的代码验证移动端的双击效果(在没有设置viewport的时候执行):
box.ondblclick = function(){
console.log('dblclick')
}
PC火狐浏览器手机模式(不仅执行dblclick事件,而且有双击放大/缩小的效果):
PC chrome/edge浏览器手机模式(不执行dblclick事件,有双击放大/缩小的效果):
IOS13真机执行效果:
Safari/火狐:能执行dblclick事件,双击放大/缩小。
Edge:能执行dblclick事件,三击放大/缩小(快速点3次)。
chrome:能执行dblclick事件,页面不缩放。
安卓via浏览器:不执行dblclick事件,双击放大/缩小。
2.touch事件
touch事件没有延迟,它是移动端特有的,pc端不支持
他有以下几个事件:
touchstart:开始触屏事件
touchmove:手指滑动事件(持续触发,只touch不滑动不会触发)
touchstend:触屏结束事件
touchcancal:触屏意外中断事件(手机中途来电?)
基本用法:
<script>
document.addEventListener("touchstart",function(){
console.log("touchstart")
})
document.addEventListener("touchmove",function(){
console.log("touchmove")
})
document.addEventListener("touchend",function(){
console.log("touchend")
})
</script>
如果在touchstart中阻止了默认事件,则onlcik事件不会被触发(阻止默认事件不要挂载到document上,浏览器可能不支持)
<script>
var box = document.querySelector(".box")
box.addEventListener("touchstart",function(e){
console.log("touchstart")
//阻止默认事件,可阻止click事件
e.preventDefault()
})
box.addEventListener("touchmove",function(e){
console.log("touchmove")
})
box.addEventListener("touchend",function(e){
console.log("touchend")
})
box.addEventListener("click",function(e){
console.log("click")
})
box.ondblclick = function(){
console.log('dblclick')
}
</script>
PC Chrome浏览器手机模式执行效果(click和dblclick都不执行,且双击时不缩放):
PC 火狐浏览器手机模式执行效果(单击时不执行click和dblclick,):
IOS13手机浏览器执行效果:
Safari/Chrome/火狐/Edge:单击/双击都不执行click和dblclick,页面不缩放(换句话说,能阻止页面缩放和click和dblclick事件)
3.touchEvent事件对象
touchEvent事件对象描述了当前事件中的一系列信息
e.target:触发事件的Dom元素,要注意的是,在同一个touch事件中,用户touch过程产生了滑动,可能touchstart碰触的元素和touchend时元素已经不是同一个,但是他们的e.target依旧指向touchstart中碰触的元素
代码:
效果:
touch事件触发时,可能有一个或多个触点,可以用下面的属性(数组)获取相应的信息:
e.touches:当前屏幕上所有触摸点的列表(只针对touchstart)
e.targetTouches:当前对象上所有触摸点的列表(只针对touchstart)
e.changedTouches:
对于 touchstart 事件, 这个 TouchList 对象列出在此次事件中新增加的触点。
对于 touchmove 事件,列出和上一次事件相比较,发生了变化的触点。
对于touchend事件,changedTouches 是已经从触摸面的离开的触点的集合(也就是说,手指已经离开了屏幕/触摸面)。
每个触点包含下面的属性:
clientX:触摸目标在视口中的x坐标。
clientY:触摸目标在视口中的y坐标。
identifier:标识触摸的唯一ID。
pageX:触摸目标在页面中的x坐标。
pageY:触摸目标在页面中的y坐标。
screenX:触摸目标在屏幕中的x坐标。
screenY:触摸目标在屏幕中的y坐标。
target:触摸的DOM节点目标。
如图:
4.onclick事件延迟的处理
实际开发中300ms的延迟让用户的体验非常不好,我们自然要把延迟去除,而click也涉及到dblclick事件,这里一并测试。
方法一: 更改默认视口宽度为设备宽度
<meta name="viewport" content="width=device-width">
PC Chrome手机模式(click延迟取消,双击不执行dblclick,双击页面不缩放):
PC 火狐手机模式(click延迟取消,双击执行dblclick,双击页面不缩放):
IOS13 真机测试:
Safari/Chrome/Edge/火狐:click大大降低,双击执行dblclick,双击页面不缩放,三击不缩放。
更改默认视口宽度后,click延迟大大降低,在真机测试中,click只比touchend落后40ms左右,dblclic大都能触发。
方法二:fastclick
原理: 在检测到touchend事件的时候,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后真正的click事件阻止掉(原理应该就是前面所说的在touchstart中阻止默认事件,所以后续的dblclick不会被执行)
屏幕适配方案中,viewport适配需要破坏完美视口,此时配合fastclick可以解决click的延迟问题
步骤:引入fastclick文件,在页面成功加载后,执行FastClick.attach()函数,并传入相应的dom元素
优点:click延迟只有1-2ms,比方法一延迟更低
缺点: 脚本相对较大
<!-- 引入fastclick -->
<script src="https://cdn.bootcss.com/fastclick/1.0.6/fastclick.js"></script>
<script>
window.onload = function(){
// 初始化,传入的参数表明整个页面中FastClick都生效
FastClick.attach(document.body)
var box = document.querySelector(".box")
var click_time,touchstart_time,touchend_time
box.ontouchstart = function(){
//获取事件触发时的时间戳
touchstart_time = new Date().getTime()
console.log('touchstart time = ' + touchstart_time)
}
box.ontouchend = function(){
//获取事件触发时的时间戳
touchend_time = new Date().getTime()
console.log('touchend time = ' + touchend_time)
}
box.onclick = function(){
//获取事件触发时的时间戳
click_time = new Date().getTime()
console.log('click time = ' + click_time)
//click一般要晚于touchend事件 我们来看看事件差
console.log(`与touchstart的时间差${click_time - touchstart_time}`)
console.log(`与touchend的时间差${click_time - touchend_time}`)
}
box.ondblclick = function(){
console.log('dblclick')
}
}
</script>
fastclick使click延迟会降低至1-2ms,安卓via依旧触发dblclick,而ios13一众浏览器都不触发
5.click与dblclick事件总结
(1)未设置视口宽度时,click事件存在300ms的延迟,而dblclick事件有些浏览器不能触发(安卓via)
(2)设置视口宽度为设备名宽度后,click时间延迟降低,降低幅度可能取决于系统。在ios13中多数浏览器都还有40ms,而安卓via只有7-8ms。ios13和安卓via都能触发dblclick事件,视口宽度不是设备宽度则不行。
(3)在touchstart事件中阻止默认事件后,ios13一众浏览器都不触发click和dblclick事件,包括安卓via。
(4)使用fastclick一般配合viewport适配,安卓via依旧触发dblclick,而ios13一众浏览器都不触发。