Touch事件
- 只针对
移动端
使用, 不支持PC端 - 主要有三个事件
-
touchstart
手指触碰屏幕的时候触发 -
touchmove
手指移动的时候触发 -
touchend
手指离开的时候
-
let oDiv = document.querySelector("div");
oDiv.addEventListener("touchstart",function () {
console.log("开始触摸");
});
oDiv.addEventListener("touchmove",function () {
console.log("移动一手指");
});
oDiv.addEventListener("touchend",function () {
console.log("结束触摸---")
});
Touch事件对象
- 我们知道PC端每一个处理事件都有一个事件对象,Touch事件也是
let oDiv = document.querySelector("div");
oDiv.addEventListener("touchstart",function (e) {
e = e || window.event;
console.log(e);
})
我们经常使用的就是
touches
,targetTouches
和changedTouches
touches
:页面上(屏幕)所有的触目点
targetTouches
:元素(容器盒子)上的触摸点,当touchend
执行的时候,event事件里面的targetTouches
不在有触摸点对象
changedTouches
:当前屏幕上刚刚接触的手指或者离开的手指
区别:
touches和targetTouches
1.如果都是将手指按到了同一个元素上
, 那么这两个对象中保存的内容是一样的
2.如果是将手指按到了不同的元素上
, 那么这个两个对象中保存的内容不一样
3.touches保存的是所有元素中的手指
, 而targetTouches保存的是当前元素中的手指
Touch事件对象中的clientX
,pageX
,screenX
-
screenX/screenY
是相对于屏幕
左上角的偏移位 -
clientX/clientY
是相对于可视区域
左上角的偏移位 -
pageX/pageY
是相对于内容
左上角的偏移位(内容区域有可能超出屏幕)
下图 可以更改的解释
clientX
,pageX
,screenX
1.红色代表screenX,
2.黄色代表pageX,蓝色的长方格是 内容区域的超出了手机屏幕
3.手绘的蓝色是clientX
也可以参考JS操作html元素中clientX、offsetX、screenX、pageX的区别一文的概述
Touch事件的点透问题
- 当一个元素放覆盖了另一个元素, 覆盖的元素监听touch事件,而下面的元素监听click事件,并且touch事件触发后覆盖的元素就消失了, 那么就会出现点透问题
注意
粉色盒子消失
,log的打印情况
需要
提醒
的是:这种情况不是 事件冒泡
,因为2个盒子是兄弟关系,不是父子关系
出现这种情况的原因是什么呢?
原因是:
1.当我们手指触摸屏幕的时候,系统会生成2个事件,一个是
touch事件
,一个是click
事件, touch事件优先click事件执行, click事件相对会延迟 100-300毫秒
2.当
touch
事件执行的时候pink粉色
盒子的display
属性更改为none
,粉色盒子消失,而click事件
在200毫秒之后,执行的时候,发现粉色盒子已经消失,那么click事件就会执行对应的触摸点
位置的box盒子,进而触发box盒子的click事件
如何解决?
这个解决其实就是
阻止事件扩散
其实就是阻止默认事件的执行event.preventDefault()
,所以需要在 粉色盒子执行touch 和 click
事件时加上
//粉色盒子
oTap.addEventListener("touchstart",function (event) {
event = event || window.event;
oTap.style.display = "none";
//阻止事件的默认行为
event.preventDefault();
});
其他的一些解决方法 第三方插件 比如:
Fastclick
专门用来解决这个问题,Zepto
插件,注意早期的Zepto
没有处理这个点透问题
关于 移动端点击事件
的封装
点击事件的特点
1.按下和离开时间不能太久 100 - 200ms
2.按下和离开距离不能(不能移动)太远 5px
3.单根手指
function Tap(dom, fn) {
if(!(dom instanceof HTMLElement)){
throw new Error("请传入一个DOM元素");
}
let startX = 0;
let startY = 0;
let startTime = 0;
dom.ontouchstart = function (event) {
// 1.判断当前元素中有几根手指
if(event.targetTouches.length > 1){
return;
}
// 2.拿到手指按下的位置
startX = event.targetTouches[0].clientX;
startY = event.targetTouches[0].clientY;
// 3.拿到手指按下的时间
startTime = Date.now();
}
dom.ontouchend = function (event) {
// 1.判断有几根手指离开了
if(event.changedTouches.length > 1){
return;
}
// 2.拿到离开手指的位置
let endX = event.changedTouches[0].clientX;
let endY = event.changedTouches[0].clientY;
// 3.判断手指离开的位置和按下位置的距离
if(Math.abs(endX - startX) > 5 ||
Math.abs(endY - startY) > 5){
return;
}
// 4.拿到手指离开的时间
let endTime = Date.now();
// 5.判断手指离开的时间和按下的时间
if(endTime - startTime > 100){
return;
}
// console.log("单击事件");
fn && fn();
}
}
- 另外的一种方式
//封装 tap事件
function tap(element,callBack) {
//记录刚开始的触摸时间
let startTime = null;
//记录结束的时间
let endTime = null;
//是否移动的标志
let isMove = false;
//触摸开始
element.addEventListener("touchstart",function (e) {
//获取当前的时间戳
startTime = Date.now();
});
//移动
element.addEventListener("touchmove",function (e) {
//移动了
isMove = true;
});
//结束
element.addEventListener("touchend",function (e) {
//获取结束的时间戳
endTime = Date.now();
if (endTime - startTime <= 200 && isMove === false){
if (callBack){
//触摸对象返回给 回调函数
callBack(e);
}
}
// 还原初始状态
isMove = false;
});
}
手动实现侧边栏
-
三层结构
组成:有一个父级盒子Div
包括一个子级盒子ul
,ul移动,ul里面包括你的内容
原理:1.手指触摸屏幕 开始
startY
记录位置 2.手指移动记录位置endy
,其结束的偏移量offsetY = endY - startY
需要注意的是: 因为你第一次和 第二次offsetY
值不同,需要一个记录变量currentY
保存上次的offsetY
,这样在下次移动的时候,就是在上一次的基础上 滚动
- 实现