touch事件
什么是touch事件?
随着智能手机和平板电脑的普及, 越来越多的人用移动设备浏览网页,我们平时在pc浏览器上用的鼠标事件,比如:click, mouseover等, 已经无法满足移动设备触摸屏的特点。
触摸时代的到来,离不开触摸事件 touch事件用于移动端,可响应用户手指(或触控笔)对屏幕或者触控板操作,给基于触控操作,给基于触控的用户界面提供可靠的支持。
手机中click事件有300ms的延迟
移动端有个两次连续“轻触”是“放大”的操作,在你第一次被“轻触”后,浏览器需要先等一段时间,若有“连续的第二次轻触”,则进行“放大”操作,否则就执行click事件,这就导致了移动端所谓的300ms
click延迟,
JavaScript dblclick 事件失效
连续快速双击元素对象时会触发此事件。
移动端由于双击缩放的存在,pc端的dblclick事件也失效了。
移动端特有的touch事件
移动端浏览器都引入了触摸(touch)事件。
最基本4个事件:
- touchstart: 当在屏幕上按下手指时触发
- touchmove: 当在屏幕上移动手指时触发
- touchend: 当手指从屏幕上离开的时候触发。
- touchcancel 当系统停止跟踪触摸的时候触发。
touchcancel : 如电话接入或者弹出信息,会取消当前的touch操作,即触发touchcancel。一般会在touchcancel时暂停游戏、存档等操作。
preventDefault()事件可以阻止滚动。
如果你使用了触摸事件,可以调用 event.preventDefault()来阻止鼠标事件被触发。
touch相关的事件跟普通的其他dom事件一样使用,可以直接用addEventListener 向指定元素添加事件。
touchstart事件
当用户手指触摸到的触摸屏的时候触发。
<div>
点击我!
</div>
<script>
var box = document.querySelector("div");
box.addEventListener("touchstart", function (e) {
console.log('touchstart');
});
</script>
touchmove事件
当用户在触摸屏上移动触点(手指)的时候,触发这个事件。一定是先要触发touchstart事件,再有可能触发 touchmove 事件。
注意: 即使手指移出了 原来的target 元素,则 touchmove 仍然会被一直触发,而且 target 仍然是原来的 target 元素。
<div>
点击我!
</div>
<script>
var box = document.querySelector("div");
box.addEventListener("touchmove", function (e) {
console.log('touchmove');
});
</script>
touchend事件
当用户的手指抬起的时候,会触发 touchend 事件。如何用户的手指从触屏设备的边缘移出了触屏设备,也会触发 touchend 事件。
<div>
点击我!
</div>
<script>
var box = document.querySelector("div");
box.addEventListener("touchend", function (e) {
console.log('touchend');
});
</script>
touchcancel事件
当触点由于某些原因被中断时触发。
几种可能的原因:
- 由于某个事件取消了触摸:例如触摸过程被一个电话打断。
- 触点离开了文档窗口,而进入了浏览器的界面元素、插件或者其他外部内容区域。
- 当用户产生的触点个数超过了设备支持的个数,从而导致 TouchList 中最早的 Touch对象被取消。
touchcancel 事件一般用于保存现场数据。比如:正在玩游戏,如果发生了 。
touchcancel事件,则应该把游戏当前状态相关的一些数据保存起来。
触摸事件对象?
TouchEvent :是描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等。
每个Touch 对象代表一个触点; 每个触点都由其位置,大小,形状,压力大小,和目标 组成。
TouchList 详解
TouchList 对象代表多个触点的一个列表。
举例来讲, 如果一个用户用三根手指接触屏幕, 与之相关的TouchList 对每根手指都会生成一个Touch对象, 共计 3 个(touches 、targetTouches、changedTouches)。
touches
一个TouchList对象,包含当前所有屏幕上的触点的Touch对象,该属性不一定是当前元素的touchstart事件触发。(单触点)
targetTouches
也是一个TouchList对象,包含从当前元素touchstart事件触发的触点Touch对象。(多触点)
changedTouches
一个TouchList对象,对于touchstart事件, 这个TouchList对象列出在此次事件中包含屏幕上新增的触点(多触点)
touches和targetTouches只存储接触屏幕的触点,touchend时,touches和targetTouches是个空数组,所以要获取触点最后离开的状态要使用changedTouches。
操作:
放1个手指在div上
先放1个手指在其他地方,然后再放1个手指在div上
先放1个手指在其他地方,然后再逐渐放2个手指在div上
每个Touch对象包含的属性:
clientX:触摸目标在视口中的x坐标。(不计算滚动条)
clientY:触摸目标在视口中的y坐标。
identifier:标识触摸的唯一ID。
pageX:触摸目标在页面中的x坐标。(包含滚动条)
pageY:触摸目标在页面中的y坐标。
screenX:触摸目标在屏幕中的x坐标。
screenY:触摸目标在屏幕中的y坐标。
target:触目的DOM节点目标。
tap事件的封装:
点击事件的封装:
- 移动端的点击事件会有300ms的延迟需要优化。
- 触屏开始时间和结束的时间差要小于150ms
- 触发点击事件是:先触发了touch事件,点击事件没有touchmove事件。
/*
* 参数说明
* el:绑定点击事件的对象
* callback: 点击事件触发后 要执行的代码
*/
//避免命名冲突
var myTouch = {
//点击事件:首先有 touchstart 事件,不能移动 touchmove,touchend结束与touchstar开始时间差,小于150ms。
tap: function (el, callback) {
var isMove = false; //是否执行了touchmove事件
var startTime = 0; //重置记录按下时的当前时间,默认为 0;
// 传的 el 必须是对象
if (typeof el === "object") {
el.addEventListener("touchstart", function () {
//按下时记录当前时间戳
startTime = new Date() * 1;
});
el.addEventListener("touchmove", function () {
isMove = true;
});
el.addEventListener("touchend", function (ev) {
//触点离开屏幕时当前的时间
var endTime = new Date() * 1;
//触点抬起时判断是否是点击的事件。
//结束时间 与 开始时间小于150ms;并且没有移动事件时为点击事件。
if((endTime - startTime) < 150 && !isMove){
//执行回调函数
//callback 是否有值 && 执行函数
callback && callback(ev,el);
}
//记录的变量恢复初始值
startTime = 0;
isMove = false;
})
}
}
}
swipe的封装
/**
* @param {object} el:添加事件的DOM元素
* @param {function} callback:单击事件执行的回调函数
* @function [封装滑动事件:左滑,右滑,上滑,下滑]
*/
swipe: function(el, dir, callback) {
var startPoint = null, // 起始点坐标
endPoint = null,
distance = 30;
// 滑动基于touchstart touchmove touchend
if (typeof el === 'object') {
// 监听事件
el.addEventListener('touchstart', function(e) {
var touchPoint = e.touches[0]; // touch对象
// 记录起始点坐标 startPoint
startPoint = {
x: touchPoint.clientX,
y: touchPoint.clientY
};
});
el.addEventListener('touchmove', function(e) {
// 记录移动后的坐标,前提是有startPoint
if (startPoint) {
var touchPoint = e.touches[0]; // touch对象
endPoint = {
x: touchPoint.clientX,
y: touchPoint.clientY
};
}
});
el.addEventListener('touchend', function() {
// console.log(startPoint, endPoint);
// 调用计算滑动方向函数
if (startPoint && endPoint && swipeDirection(startPoint, endPoint) === dir) {
callback && callback();
}
clearSwipe();
});
// 判断滑动方法
/*
计算起始与结束的差值
判断滑动是水平还是垂直
*/
function swipeDirection(start, end) {
var diffX = end.x - start.x; // 水平差值
var diffY = end.y - start.y; // 垂直差值
// 求绝对值
var absX = Math.abs(diffX);
var absY = Math.abs(diffY);
var direction = '';
// 判断是否算滑动 差值 > 30
if (absX > distance || absY > distance) {
// 判断水平还是垂直
if (absX > absY) { // 水平滑动
direction = diffX > 0 ? 'swipeLeft' : 'swipeRight';
} else {
direction = diffY > 0 ? 'swipeUp' : 'swipeDown';
}
}
return direction;
}
/*
* @function [清除数据]
*/
function clearSwipe() {
startPoint = null;
endPoint = null;
}
}
}