小程序踩坑记——长按与点击事件冲突
2017-02-12 13:03 阅读(250)

在小程序中,通过设置bindtap 属性,就能绑定点击事件

// wxml
<view bindtap="bindTap">点我</view>
// js
bindTap: function(e) {
    console.log("点击");
}

上面简单实现了单击事件的绑定

同样,长按事件的绑定也很简单

// wxml
<view bindlongtap="bindLongTap">长按我</view>
// js
bindLongTap: function(e) {
    console.log("长按");
}

根据文档,手指触摸后,超过350ms再离开就会执行长按事件

看上面的demo,好像没有什么毛病,实现起来非常简单

但是,在实际开发的过程中,比如说微信的对话界面,点击的时候需要打开对话界面,而长按的时候需要弹出一个菜单(ios滑动另说,小程序中没有列表滑动api),这时候就需要同时处理点击和长按事件

你可能会说,同时绑定bindtap 和 bindlongtap 事件不就好了吗?

// wxml
<view bindtap="bindTap" bindlongtap="bindLongTap">撸我</view>
// js

bindTap: function(e) {
    console.log("点击");
}

bindLongTap: function(e) {
    console.log("长按");
}

运行之后,你会发现,会先执行“长按”后,紧接着松开的时候会执行“点击”

看个演示

上面例子中,长按事件会显示一个菜单,而点击事件则是跳转到编辑界面,明显这里有事件冲突了

通过测试,我们发现,小程序中事件执行的顺序是

点击:touchstart → touchend → tap
长按 touchstart → longtap → touchend → tap

可以发现,实际上每个事件,最后都会去执行tap事件

这tm就尴尬了,看来正常的事件绑定是行不通了

根据事件执行的顺序,touchstart、touchend 和 tap 事件是必须执行的,在看看长按执行的条件

手指触摸后,超过350ms再离开

那么我们是不是可以自己来实现长按呢?

通过touchstart 和 touchend 的时间节点,来判断是点击还是长按

// wxml
<view bindtouchstart="bindTouchStart" bindtouchend="bindTouchEnd" bindtap="bindTap">蹂躏我</view>
// js
bindTouchStart: function(e) {
    this.startTime = e.timeStamp;
}

bindTouchEnd: function(e) {
    this.endTime = e.timeStamp;
}

bindTap: function(e) {
    if(this.endTime  - this.startTime > 350) {
        console.log("长按");
    } else {
        console.log("点击")
    }
}

看下实际项目中的例子

你会发现这样做的话,菜单的弹出会在松手之后,这样体验不太好,所以长按事件我们还必须保留

// wxml
<view bindtouchstart="bindTouchStart" bindtouchend="bindTouchEnd" bindlongtap="bingLongTap" bindtap="bindTap">蹂躏我</view>
// js
bindTouchStart: function(e) {
    this.startTime = e.timeStamp;
}

bindTouchEnd: function(e) {
    this.endTime = e.timeStamp;
}

bindTap: function(e) {
    if(this.endTime  - this.startTime < 350) {
        console.log("点击")
    }
}

bingLongTap: function(e) {
    console.log("长按");
}

看一下

比较完美的解决了

对于事件传递小程序还有待加强,可以类似android那样控制事件是否继续往下传递就好了

如果您有更高的方法,请告诉我