1

问题描述

最近在开发一个视频播放器项目,需要隐藏 video 标签,使用 canvas 自己做渲染。结果在点按钮播放视频的时候发现 zepto touch 模块不能用了。

调试结果

看了一下错误提示,发现手机浏览器只允许用户操作打开 video,换句话说不管你最终是哪个函数执行了 video.play(),你的调用栈上溯到最开始一定是一个 DOM 元素的 UI 事件回调。

但是zepto touch 模块是这么封装 tap 事件的:

    tapTimeout = setTimeout(function() {

      // trigger universal 'tap' with the option to cancelTouch()
      // (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
      var event = $.Event('tap')
      event.cancelTouch = cancelAll
      // [by paper] fix -> "TypeError: 'undefined' is not an object (evaluating 'touch.el.trigger'), when double tap
      if (touch.el) touch.el.trigger(event)

      // trigger double tap immediately
      if (touch.isDoubleTap) {
        if (touch.el) touch.el.trigger('doubleTap')
        touch = {}
      }

      // trigger single tap after 250ms of inactivity
      else {
        touchTimeout = setTimeout(function(){
          touchTimeout = null
          if (touch.el) touch.el.trigger('singleTap')
          touch = {}
        }, 250)
      }
    }, 0)

使用 setTimeout 异步执行函数,导致调用栈被清空了,系统判断的时候自然不会认为是用户操作导致的 video.play()。

修改方案

那么比较粗暴的解决方法就是修改 zepto 代码,把 tap 事件的激发动作从异步回调中移出来同步执行,具体的说就是这三行:

      var event = $.Event('tap')
      event.cancelTouch = cancelAll
      if (touch.el) touch.el.trigger(event)

因为 tap 事件是没有什么延时的,所以直接移出来不会有什么影响,如果是延时事件就很尴尬了,暂时还想不出来什么解决方法。


Y3G
458 声望14 粉丝

桌面软件、 web前端、 移动app混合开发、 安防行业技术