在PC端上的JS事件相信大家已经熟悉不少,诸如clickmouseover这类事件,都可以满足交互的需要,虽然移动端上的事件可能平常稍有接触,但是可能不太了解其中具体的用法区别。
前言:
这几个事件最早出现于IOS safari中,为了向开发人员转达一些特殊的信息,所以新增了这些事件,随着Android中的webkit的加入,慢慢地这样的专有事件成了事实的标准,从而导致W3C开始指定Touch Event规范的内容。
具体说来有这样几个事件:
- touchstart 手指触摸屏幕时触发,即使已经有手指在屏幕上也会触发。
- touchmove 手指在屏幕滑动时触发。
- touchend 手指从屏幕时移开时触发。
事件定义的方式:
大致上分为DOM0事件和DOM2事件两种.
DMO0事件,就是传统的直接将事件作为属性设置的形式:
div1.ontouchstart = function(){
alert(1);
}
DOM2事件,则是用addEventListener的方式来绑定事件处理程序:
div1.addEventListener("touchstart",function(){
alert(1);
});
大多数时候不推崇第一种方式,这种方式在移动端使用时好时坏,不建议使用。
PC的事件比移动端上的事件响应的慢300ms:
在早期的手机上,浏览器为了能够实现放大和缩放功能,采用双击的方式来达到这样的交互效果,为了实现这样的效果,浏览器需要判断用户在第一次触碰屏幕之后,是否在300ms之内再次点击,有则表明用户希望缩放和放大,所以click事件会推迟到300ms之后运行。
var div = document.querySelector("#div");
div.onclick = function(){
console.log("click!");
}
div.ontouchstart = function(){
console.log("touchstart!");
}
可以看到每次点击,touchstart总会先于click事件运行。 当然这方面的问题有专门的库用于解决延迟的问题。诸如:Fastclick
点击穿透问题:
这个问题在当有一个绝对定位或固定定位元素绑定了touch事件,那么覆盖在他之下的具有点击特性的元素也会被触发。
比如:
有一个遮罩层A元素,他的底下有一个链接元素B.
当这个遮罩层点击之后希望遮罩层消失,真实的状况是这时候点击遮罩层不见的同时会跳转页面。
这是为什么? 前面说过了touchstart会先于click事件执行,当上述的这个遮罩层消失在300ms之内消失时,那么他底下的具有点击特性的元素会被触发。大家可以私下模拟上述的例子。
如何解决?
下层元素不使用点击特性的元素
我可以去某宝的移动版网站上看,他首页使用的多层的DIV来代替A标签
这种方法不太推荐,因为a标签能够为SEO提供一些信息
阻止所有点击:
document.addEventListener("click",function(ev){
ev.preventDefault();
})
document.addEventListener("touchstart",function(ev){
ev.preventDefault();
})
这时候的有点击特性的元素的交互行为将会失效,当然也可以根据实际需要重新开启交互行为。
代码如下:
a.ontouchstart = function(){
window.location = this.href;
}
这样既兼顾了SEO又可以安然使用点击事件。当然它还有其他的好处。
- 能够阻止IOS10缩放: 对于ISO10设置meta标签禁止缩放是没有作用的,上面的代码阻止了浏览器的默认行为。
- 阻止IOS10下回弹效果
- 去除系统滚动条
- 禁止长按选中文字和图片:当然也同时阻止了input获取焦点的行为,这就需要使用单独为input添加一个阻止冒泡的行为。以免事件冒泡至顶层元素而被阻止交互行为。
input.ontouchstart = function(ev){
ev.stopPropagation();
}
移动端事件对象:
注意到前面的例子里每一个事件处理程序都有一个evt的参数了吗,那是有关于当前触摸的相关信息,通过这样一个对象,能够获取到当前触碰的坐标,触碰的手指个数等等。 其中最重要的常用的莫过于手指列表了。
touches:当前位于屏幕下的手指列表信息
targetTouches: 当前位于当前元素下的手指列表信息
changedTouches: 当前涉及到当前事件的手指列表
这三个手指列表都存在触碰事件对象里面,在每次发生触碰之后这里的列表都会更新。
var div = document.querySelector("#div");
div.ontouchmove = function(evt){
this.innerHTML = `
touches-length:${evt.touches.length}
targetTouches-length:${evt.targetTouches.length}
changedTouches-length:${evt.changedTouches.length}
`
console.log(evt);
}
以上实例,在手指移动于DIV上之后会更新DIV的内容。 分别展示了touches、targetTouches、changedTouches的手指个数
感谢阅读!希望能共同进步!