問題描述:
項目在祖先元素上綁定了 touchstart,touchmove,touchend事件,用來處理全局性的事件,比如滑動翻頁
正常狀態下:
- 用戶在子元素上有交互動作時,默認狀態下都是會冒泡到祖先元素響應
特定情況下:
- 子元素單獨綁定了事件
- 特性情況下需要阻止全局事件
常規的做法就是stopPropagation阻止即可
但如果子元素綁定的是 click,touchmove,touchend這類事件的話,問題就來了
全局的touchstart事件也會被冒泡觸發
發一段項目圖:
/** * ppt事件接口 * * 允許用戶自定義其行為 * 1 支持14種操作行為 * 2 默認對象都具有滑動翻頁的特性 * 3 翻頁的特性在遇到特性的情況可以被覆蓋 * 比如 * 行為1:用戶定義該名字可以支持 click 點擊行為, 那么該元素左右滑動能過翻頁 * 行為2:用戶如果定義swipeLeft 行為,該元素左右滑動將不會翻頁,因為默認翻頁已經被覆蓋 * * 此接口函數有作用域隔離 */ Xut.define('Xut.PPTevent', { //數據庫預定義14個事件接口 defauleEventType: ['null', 'auto', 'tap', 'drag', 'dragTag', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'longTap', 'mTouchMagnify', 'mTouchNarrow', 'mTouchRotate' ], //綁定事件 bind: function(element, evtName, fn) { element.on(Xut.START_EV, function(e) { //阻止 mousedown事件冒泡 e.stopPropagation(); }); element.on(evtName, fn); //綁定真正事件 },
on綁定的事件替換成硬編碼容易理解
bind: function(element, evtName, fn) { element.on('mousedown', function(e) { //阻止 mousedown事件冒泡 e.stopPropagation(); }); element.on('swipeLeft', fn); //綁定真正事件 },
給元素綁定'swipeLeft'滑動事件,同時阻止'mousedown'冒泡到祖先元素,此時理論上就可行了
這樣處理之后zepto移動事件確失效了
Zepto事件綁定
$(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 if (Math.abs(touch.x1 - touch.x2) > 10) e.preventDefault() }) .bind('touchend', function(e){ cancelLongTap()
zepto移動事件失效的根源找到了,不能阻止事件冒泡了,不能攔截了
偏偏Zepto不讓你這么安逸,學jquery的live()方法一樣,把事件給綁到body元素上了, jquery1.7后就去掉了,zepto你也要跟上呀
處理的辦法:
子元素上增加一個hack標記, 控制器冒泡過濾排除
onTouchStart: function (e) { var point = Xut.hasTouch ? e.touches[0] : e; if (!point) return; this.bindDefaultEventId = null; var children = point.target.offsetParent.children[0]; //處理默認特性 if (children.getAttribute('bindDefaultEvent')) { this.bindDefaultEventId = children.id; } else { var className = point.target.className; if (className && className === 'triggerAction') { //Actoin熱點,通過冒泡捕獲到 } else { if (className !== 'widgetwapper') { this.start = void 0; return; } } }