问题描述
最近在开发一个视频播放器项目,需要隐藏 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 事件是没有什么延时的,所以直接移出来不会有什么影响,如果是延时事件就很尴尬了,暂时还想不出来什么解决方法。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。