项目需求:
(移动端项目中)长按聊天消息,出现一个弹出层,进行消息撤回操作,点击弹出层之外的其他地方需要隐藏该弹出层。
基础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()
}
}
},
==到此为止,应该是满足了我的需求了==
感谢您的阅读
如有不对,欢迎指正。如有其他实现方法,欢迎留言讨论~