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

5,440 阅读1分钟

个人博客查看文章点这里

项目需求:

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

基础html代码:

<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>

需求实现:

    // 通过定时器,只有长按超过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==中的代码

    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==中做处理,如果长按时间短,就用代码触发图片的点击事件,长按时间长,就不触发图片的点击事件。

修改前面的代码:


   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()
         }

       }
     },

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

感谢您的阅读

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