看了同事写的一个jquerytap插件,模仿pc端的点击事件,但未解决点击穿透问题.
又熟悉了jquery自定义事件的写法
/*!
* 模拟原生的点击事件
*/
/**
点击穿透的解决
if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
// Prevent any user-added listeners declared on FastClick element from being fired.
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
} else {
// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
event.propagationStopped = true;
}
// Cancel the event
event.stopPropagation();
event.preventDefault();
return false;
}
*/
(function($, specialEventName) {
'use strict';
var nativeEvent = Object.create(null),
vague = 5; // 允许触摸误差
// 防止pc上调试时候点击不触发
if ('ontouchstart' in document) {
nativeEvent.start = 'touchstart';
nativeEvent.ing = 'touchmove';
nativeEvent.end = 'touchend';
} else {
nativeEvent.start = 'mousedown';
nativeEvent.ing = 'mouseover';
nativeEvent.end = 'mouseup';
}
// jq自定义事件
$.event.special[specialEventName] = {
setup: function(data, namespaces, eventHandle) {
var $element = $(this);
var eventData = {};
var forbiddenNativeTap = false;
// 提供不触发横向原生点击的可能
if ($element.hasClass('forbiddenNativeTap')) {
forbiddenNativeTap = true;
}
$element
// 收集事件对象
.on(nativeEvent.start + ' ' + nativeEvent.ing + ' ' + nativeEvent.end, function(event) {
//区别手机端和px端event
eventData.event = event.originalEvent.changedTouches ? event.originalEvent.changedTouches[0] : event;
})
.on(nativeEvent.start, function(event) {
if (event.which && event.which !== 1) {
return;//非移动端端
}
if (data) {
// delegate 事件委托
var $target = $(eventData.event.target);
if ($target.is(data)) {
$target.addClass('global-tap-element-highlight')
} else {
$target.parentsUntil($element, data).addClass('global-tap-element-highlight');
}
} else {
$(this).addClass('global-tap-element-highlight');
}
eventData.target = event.target;
eventData.startX = eventData.event.pageX;
eventData.startY = eventData.event.pageY;
})
.on(nativeEvent.ing, function(event) {
eventData.pageX = eventData.event.pageX;
eventData.pageY = eventData.event.pageY;
if (data) {
// delegate 事件委托
var $target = $(eventData.event.target);
if ($target.is(data)) {
$target.removeClass('global-tap-element-highlight')
} else {
$target.parentsUntil($element, data).removeClass('global-tap-element-highlight');
}
} else {
if (eventData.pageY !== eventData.startY) {
$(this).removeClass('global-tap-element-highlight');
}
}
})
.on(nativeEvent.end, function(event) {
// 对比touchstart和touchend的位置和target
// 横向移动依然触发
event.type = specialEventName;
event.pageX = eventData.event.pageX;
event.pageY = eventData.event.pageY;
if (forbiddenNativeTap) {
if (eventData.target === event.target && eventData.startY === eventData.event.pageY && eventData.startX === eventData.event.pageX) {
eventHandle.call(this, event);
}
} else {
if (eventData.target === event.target && Math.abs(eventData.startY - eventData.event.pageY) <= vague) {
eventHandle.call(this, event);
}
}
if (data) {
// delegate 事件委托
var $target = $(eventData.event.target);
if ($target.is(data)) {//is方法决定是否匹配data表达式
$target.removeClass('global-tap-element-highlight')
} else {
$target.parentsUntil($element, data).removeClass('global-tap-element-highlight');
}
} else {
$(this).removeClass('global-tap-element-highlight');
}
});
},
remove: function() {
$(this).off(nativeEvent.start + ' ' + nativeEvent.ing + ' ' + nativeEvent.end);
}
};
//dom 元素直接调用.tap() 触发,tap(callback) //绑定
$.fn[specialEventName] = function(fn) {
return this[fn ? 'on': 'trigger'](specialEventName, fn);
};
})(jQuery, 'tap');