JavaScript-移动设备上CSS3动画带来的touch事件响应问题

UI设计界面 UI设计界面 主题:1059 回复:2190

JavaScript-移动设备上CSS3动画带来的touch事件响应问题

偏爱自由 发布于 2016-10-29 字数 616 浏览 1181 回复 1

系统中本来趋于完善了,一些触摸事件原本都是用的touchend,后来产品同学认为不够炫,要动起来,于是重构同学发挥了才能,加了很多css3 transition/animation等,然后……然后…… 事件就跑不起来了……

最后经过各种调试才发现,只有改成touchstart才能相应到。猜测:元素动画播放的时间轴和js事件响应应该是同时进行的,并且播放动画时元素是从render树中抽离了的,类似于display:none; 只有等到动画播放完了才重新回到render树中,因此如果用touchend,只有等动画设定的时间结束了之后再拿起手指,才能响应到。但是总感觉这样多少有些别捏,有其他同学遇到这一类问题吗? 希望能有交流, thanks.

以上基于webkit的浏览器,非webkit的没试过。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

支持 Markdown 语法,需要帮助?

评论(1

清晨说ぺ晚安 2017-03-10 1 楼

如果是手指单击事件 不要用touchstart或者touchend 两者都不准确 也不太靠谱
应该用tap事件 而tap事件是不存在的 所以我们需要自定义这个tap事件
zeptojs里面已经实现了这些事件 不仅仅是tap 包括swipe等.
其原理也很简单 代码没几行 可以直接看他源码参考

var touch = {}, touchTimeout

function parentIfText(node){
return 'tagName' in node ? node : node.parentNode
}

function swipeDirection(x1, x2, y1, y2){
var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2)
return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
}

var longTapDelay = 750, longTapTimeout

function longTap(){
longTapTimeout = null
if (touch.last) {
touch.el.trigger('longTap')
touch = {}
}
}

function cancelLongTap(){
if (longTapTimeout) clearTimeout(longTapTimeout)
longTapTimeout = null
}

$(document).ready(function(){
var now, delta

$(document.body).bind('touchstart', function(e){
  now = Date.now()
  delta = now - (touch.last || now)
  touch.el = $(parentIfText(e.touches[0].target))
  touchTimeout && clearTimeout(touchTimeout)
  touch.x1 = e.touches[0].pageX
  touch.y1 = e.touches[0].pageY
  if (delta > 0 && delta <= 250) touch.isDoubleTap = true
  touch.last = now
  longTapTimeout = setTimeout(longTap, longTapDelay)
}).bind('touchmove', function(e){
  cancelLongTap()
  touch.x2 = e.touches[0].pageX
  touch.y2 = e.touches[0].pageY
}).bind('touchend', function(e){
   cancelLongTap()

  // double tap (tapped twice within 250ms)
  if (touch.isDoubleTap) {
    touch.el.trigger('doubleTap')
    touch = {}

  // swipe
  } else if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
             (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) {
    touch.el.trigger('swipe') &&
      touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
    touch = {}

  // normal tap
  } else if ('last' in touch) {
    touch.el.trigger('tap')

    touchTimeout = setTimeout(function(){
      touchTimeout = null
      touch.el.trigger('singleTap')
      touch = {}
    }, 250)
  }
}).bind('touchcancel', function(){
  if (touchTimeout) clearTimeout(touchTimeout)
  if (longTapTimeout) clearTimeout(longTapTimeout)
  longTapTimeout = touchTimeout = null
  touch = {}
})

})

;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){
$.fn[m] = function(callback){ return this.bind(m, callback) }
})

这是自定义的全部事件 如果只要tap一个 代码就更短