123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /**
- * 仅提供简单的on,off(仅支持事件委托,不支持当前元素绑定,当前元素绑定请直接使用addEventListener,removeEventListener)
- * @param {Object} $
- */
- (function($) {
- if ('ontouchstart' in window) {
- $.isTouchable = true;
- $.EVENT_START = 'touchstart';
- $.EVENT_MOVE = 'touchmove';
- $.EVENT_END = 'touchend';
- } else {
- $.isTouchable = false;
- $.EVENT_START = 'mousedown';
- $.EVENT_MOVE = 'mousemove';
- $.EVENT_END = 'mouseup';
- }
- $.EVENT_CANCEL = 'touchcancel';
- $.EVENT_CLICK = 'click';
- var _mid = 1;
- var delegates = {};
- //需要wrap的函数
- var eventMethods = {
- preventDefault: 'isDefaultPrevented',
- stopImmediatePropagation: 'isImmediatePropagationStopped',
- stopPropagation: 'isPropagationStopped'
- };
- //默认true返回函数
- var returnTrue = function() {
- return true
- };
- //默认false返回函数
- var returnFalse = function() {
- return false
- };
- //wrap浏览器事件
- var compatible = function(event, target) {
- if (!event.detail) {
- event.detail = {
- currentTarget: target
- };
- } else {
- event.detail.currentTarget = target;
- }
- $.each(eventMethods, function(name, predicate) {
- var sourceMethod = event[name];
- event[name] = function() {
- this[predicate] = returnTrue;
- return sourceMethod && sourceMethod.apply(event, arguments)
- }
- event[predicate] = returnFalse;
- }, true);
- return event;
- };
- //简单的wrap对象_mid
- var mid = function(obj) {
- return obj && (obj._mid || (obj._mid = _mid++));
- };
- //事件委托对象绑定的事件回调列表
- var delegateFns = {};
- //返回事件委托的wrap事件回调
- var delegateFn = function(element, event, selector, callback) {
- return function(e) {
- //same event
- var callbackObjs = delegates[element._mid][event];
- var handlerQueue = [];
- var target = e.target;
- var selectorAlls = {};
- for (; target && target !== document; target = target.parentNode) {
- if (target === element) {
- break;
- }
- if (~['click', 'tap', 'doubletap', 'longtap', 'hold'].indexOf(event) && (target.disabled || target.classList.contains($.className('disabled')))) {
- break;
- }
- var matches = {};
- $.each(callbackObjs, function(selector, callbacks) { //same selector
- selectorAlls[selector] || (selectorAlls[selector] = $.qsa(selector, element));
- if (selectorAlls[selector] && ~(selectorAlls[selector]).indexOf(target)) {
- if (!matches[selector]) {
- matches[selector] = callbacks;
- }
- }
- }, true);
- if (!$.isEmptyObject(matches)) {
- handlerQueue.push({
- element: target,
- handlers: matches
- });
- }
- }
- selectorAlls = null;
- e = compatible(e); //compatible event
- $.each(handlerQueue, function(index, handler) {
- target = handler.element;
- var tagName = target.tagName;
- if (event === 'tap' && (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'SELECT')) {
- e.preventDefault();
- e.detail && e.detail.gesture && e.detail.gesture.preventDefault();
- }
- $.each(handler.handlers, function(index, handler) {
- $.each(handler, function(index, callback) {
- if (callback.call(target, e) === false) {
- e.preventDefault();
- e.stopPropagation();
- }
- }, true);
- }, true)
- if (e.isPropagationStopped()) {
- return false;
- }
- }, true);
- };
- };
- var findDelegateFn = function(element, event) {
- var delegateCallbacks = delegateFns[mid(element)];
- var result = [];
- if (delegateCallbacks) {
- result = [];
- if (event) {
- var filterFn = function(fn) {
- return fn.type === event;
- }
- return delegateCallbacks.filter(filterFn);
- } else {
- result = delegateCallbacks;
- }
- }
- return result;
- };
- var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/;
- /**
- * mui delegate events
- * @param {type} event
- * @param {type} selector
- * @param {type} callback
- * @returns {undefined}
- */
- $.fn.on = function(event, selector, callback) { //仅支持简单的事件委托,主要是tap事件使用,类似mouse,focus之类暂不封装支持
- return this.each(function() {
- var element = this;
- mid(element);
- mid(callback);
- var isAddEventListener = false;
- var delegateEvents = delegates[element._mid] || (delegates[element._mid] = {});
- var delegateCallbackObjs = delegateEvents[event] || ((delegateEvents[event] = {}));
- if ($.isEmptyObject(delegateCallbackObjs)) {
- isAddEventListener = true;
- }
- var delegateCallbacks = delegateCallbackObjs[selector] || (delegateCallbackObjs[selector] = []);
- delegateCallbacks.push(callback);
- if (isAddEventListener) {
- var delegateFnArray = delegateFns[mid(element)];
- if (!delegateFnArray) {
- delegateFnArray = [];
- }
- var delegateCallback = delegateFn(element, event, selector, callback);
- delegateFnArray.push(delegateCallback);
- delegateCallback.i = delegateFnArray.length - 1;
- delegateCallback.type = event;
- delegateFns[mid(element)] = delegateFnArray;
- element.addEventListener(event, delegateCallback);
- if (event === 'tap') { //TODO 需要找个更好的解决方案
- element.addEventListener('click', function(e) {
- if (e.target) {
- var tagName = e.target.tagName;
- if (!preventDefaultException.test(tagName)) {
- if (tagName === 'A') {
- var href = e.target.href;
- if (!(href && ~href.indexOf('tel:'))) {
- e.preventDefault();
- }
- } else {
- e.preventDefault();
- }
- }
- }
- });
- }
- }
- });
- };
- $.fn.off = function(event, selector, callback) {
- return this.each(function() {
- var _mid = mid(this);
- if (!event) { //mui(selector).off();
- delegates[_mid] && delete delegates[_mid];
- } else if (!selector) { //mui(selector).off(event);
- delegates[_mid] && delete delegates[_mid][event];
- } else if (!callback) { //mui(selector).off(event,selector);
- delegates[_mid] && delegates[_mid][event] && delete delegates[_mid][event][selector];
- } else { //mui(selector).off(event,selector,callback);
- var delegateCallbacks = delegates[_mid] && delegates[_mid][event] && delegates[_mid][event][selector];
- $.each(delegateCallbacks, function(index, delegateCallback) {
- if (mid(delegateCallback) === mid(callback)) {
- delegateCallbacks.splice(index, 1);
- return false;
- }
- }, true);
- }
- if (delegates[_mid]) {
- //如果off掉了所有当前element的指定的event事件,则remove掉当前element的delegate回调
- if ((!delegates[_mid][event] || $.isEmptyObject(delegates[_mid][event]))) {
- findDelegateFn(this, event).forEach(function(fn) {
- this.removeEventListener(fn.type, fn);
- delete delegateFns[_mid][fn.i];
- }.bind(this));
- }
- } else {
- //如果delegates[_mid]已不存在,删除所有
- findDelegateFn(this).forEach(function(fn) {
- this.removeEventListener(fn.type, fn);
- delete delegateFns[_mid][fn.i];
- }.bind(this));
- }
- });
- };
- })(mui);
|