移动端的touch事件和click事件遇到的坑

(移动端项目中)长按聊天消息,出现一个弹出层,进行消息撤回操作,点击弹出层之外的其他地方需要隐藏该弹出层。记录下这里遇到的坑。

项目需求:

(移动端项目中)长按聊天消息,出现一个弹出层,进行消息撤回操作,点击弹出层之外的其他地方需要隐藏该弹出层。

基础html代码:

1
2
3
4
5
6
7
8
9
10
<div>
<ul class="press-operation">
<li>复制</li>
<li>撤回</li>
</ul>
<div @touchstart="keepPress($event)" @touchmove="" @touchend="keepPressEnd($event)" @touchcancel="">
<img class="img" src="" />
</div>
</div>

需求实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 通过定时器,只有长按超过500ms是才进行需要的操作
// 按下时触发
keepPress(event){
let nodeEl = event.currentTarget.parentElement.firstElementChild
this.pressTimer = setInterval(() => {
nodeEl.style.display = 'block'
},500)
}
// 松开时触发
keepPressEnd(event){
clearInterval(this.pressTimer)
},

// 点击弹出层其他地方关闭弹出层
document.addEventListener('click',function () {
$('.press-operation').hide()
})

问题一:

在安卓中,上面的代码能实现我们的需求,但是,在IOS中,长按松开后,弹出层就立马关闭了!!!****

了解了下touch和click事件:

touchstart:

  • touchstart 手指触碰开始就能触发

click:

  • 1.手指触碰
  • 2.手指未在屏幕上移动
  • 3.在这个dom上手指离开屏幕
  • 4.触摸和离开屏幕之间的时间间隔较短

上网一顿搜索发现touch和click的执行顺序:

touchstart –> touchmove –> touchend –> touchcancel –> click

所以,执行完touch事件后会执行click事件,在ios中就会出现长按松开后就会关闭弹出层。这里我们需要阻止touch事件的默认行为使用event.preventDefault()

修改下keepPress中的代码

1
2
3
4
5
6
7
8
keepPress(event){
event.preventDefault() // <**添加了这句
let nodeEl = event.currentTarget.parentElement.firstElementChild
this.pressTimer = setInterval(() => {
nodeEl.style.display = 'block'
},500)
}

这样代码就能满足我们的需求了。

问题二:

当我们发送的消息是图片消息时,我们需要点击图片放大,长按图片也出现撤销的弹出层。通过前面的分析,当click和touch事件同时存在时会先触发touch,再触发click**** 。因为我们阻止了touch事件的默认行为,所以,我们点击图片的时候并不会触发click事件,图片也就不会放大。

这里我们需要在touchend中做处理,如果长按时间短,就用代码触发图片的点击事件,长按时间长,就不触发图片的点击事件。

修改前面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
keepPress(event){
event.preventDefault()
this.pressTime = 0 // 清0计数器
$('.press-operation').hide() // 每次长按会先隐藏所有的弹出层
let nodeEl = event.currentTarget.parentElement.firstElementChild
this.pressTimer = setInterval(() => {
this.pressTime = this.pressTime + 1
nodeEl.style.display = 'block'
},500)
},
keepPressEnd(event){
let el = event.currentTarget.getElementsByClassName('img')[0]
clearInterval(this.pressTimer)
if(this.pressTime < 1){ // 长按时间不足500ms时,触发点击事件
if(el){
el.click()
}

}
},

到此为止,应该是满足了我的需求了

感谢您的阅读

如有不对,欢迎指正。如有其他实现方法,欢迎留言讨论~