mui.event.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /**
  2. * 仅提供简单的on,off(仅支持事件委托,不支持当前元素绑定,当前元素绑定请直接使用addEventListener,removeEventListener)
  3. * @param {Object} $
  4. */
  5. (function($) {
  6. if ('ontouchstart' in window) {
  7. $.isTouchable = true;
  8. $.EVENT_START = 'touchstart';
  9. $.EVENT_MOVE = 'touchmove';
  10. $.EVENT_END = 'touchend';
  11. } else {
  12. $.isTouchable = false;
  13. $.EVENT_START = 'mousedown';
  14. $.EVENT_MOVE = 'mousemove';
  15. $.EVENT_END = 'mouseup';
  16. }
  17. $.EVENT_CANCEL = 'touchcancel';
  18. $.EVENT_CLICK = 'click';
  19. var _mid = 1;
  20. var delegates = {};
  21. //需要wrap的函数
  22. var eventMethods = {
  23. preventDefault: 'isDefaultPrevented',
  24. stopImmediatePropagation: 'isImmediatePropagationStopped',
  25. stopPropagation: 'isPropagationStopped'
  26. };
  27. //默认true返回函数
  28. var returnTrue = function() {
  29. return true
  30. };
  31. //默认false返回函数
  32. var returnFalse = function() {
  33. return false
  34. };
  35. //wrap浏览器事件
  36. var compatible = function(event, target) {
  37. if (!event.detail) {
  38. event.detail = {
  39. currentTarget: target
  40. };
  41. } else {
  42. event.detail.currentTarget = target;
  43. }
  44. $.each(eventMethods, function(name, predicate) {
  45. var sourceMethod = event[name];
  46. event[name] = function() {
  47. this[predicate] = returnTrue;
  48. return sourceMethod && sourceMethod.apply(event, arguments)
  49. }
  50. event[predicate] = returnFalse;
  51. }, true);
  52. return event;
  53. };
  54. //简单的wrap对象_mid
  55. var mid = function(obj) {
  56. return obj && (obj._mid || (obj._mid = _mid++));
  57. };
  58. //事件委托对象绑定的事件回调列表
  59. var delegateFns = {};
  60. //返回事件委托的wrap事件回调
  61. var delegateFn = function(element, event, selector, callback) {
  62. return function(e) {
  63. //same event
  64. var callbackObjs = delegates[element._mid][event];
  65. var handlerQueue = [];
  66. var target = e.target;
  67. var selectorAlls = {};
  68. for (; target && target !== document; target = target.parentNode) {
  69. if (target === element) {
  70. break;
  71. }
  72. if (~['click', 'tap', 'doubletap', 'longtap', 'hold'].indexOf(event) && (target.disabled || target.classList.contains($.className('disabled')))) {
  73. break;
  74. }
  75. var matches = {};
  76. $.each(callbackObjs, function(selector, callbacks) { //same selector
  77. selectorAlls[selector] || (selectorAlls[selector] = $.qsa(selector, element));
  78. if (selectorAlls[selector] && ~(selectorAlls[selector]).indexOf(target)) {
  79. if (!matches[selector]) {
  80. matches[selector] = callbacks;
  81. }
  82. }
  83. }, true);
  84. if (!$.isEmptyObject(matches)) {
  85. handlerQueue.push({
  86. element: target,
  87. handlers: matches
  88. });
  89. }
  90. }
  91. selectorAlls = null;
  92. e = compatible(e); //compatible event
  93. $.each(handlerQueue, function(index, handler) {
  94. target = handler.element;
  95. var tagName = target.tagName;
  96. if (event === 'tap' && (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'SELECT')) {
  97. e.preventDefault();
  98. e.detail && e.detail.gesture && e.detail.gesture.preventDefault();
  99. }
  100. $.each(handler.handlers, function(index, handler) {
  101. $.each(handler, function(index, callback) {
  102. if (callback.call(target, e) === false) {
  103. e.preventDefault();
  104. e.stopPropagation();
  105. }
  106. }, true);
  107. }, true)
  108. if (e.isPropagationStopped()) {
  109. return false;
  110. }
  111. }, true);
  112. };
  113. };
  114. var findDelegateFn = function(element, event) {
  115. var delegateCallbacks = delegateFns[mid(element)];
  116. var result = [];
  117. if (delegateCallbacks) {
  118. result = [];
  119. if (event) {
  120. var filterFn = function(fn) {
  121. return fn.type === event;
  122. }
  123. return delegateCallbacks.filter(filterFn);
  124. } else {
  125. result = delegateCallbacks;
  126. }
  127. }
  128. return result;
  129. };
  130. var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/;
  131. /**
  132. * mui delegate events
  133. * @param {type} event
  134. * @param {type} selector
  135. * @param {type} callback
  136. * @returns {undefined}
  137. */
  138. $.fn.on = function(event, selector, callback) { //仅支持简单的事件委托,主要是tap事件使用,类似mouse,focus之类暂不封装支持
  139. return this.each(function() {
  140. var element = this;
  141. mid(element);
  142. mid(callback);
  143. var isAddEventListener = false;
  144. var delegateEvents = delegates[element._mid] || (delegates[element._mid] = {});
  145. var delegateCallbackObjs = delegateEvents[event] || ((delegateEvents[event] = {}));
  146. if ($.isEmptyObject(delegateCallbackObjs)) {
  147. isAddEventListener = true;
  148. }
  149. var delegateCallbacks = delegateCallbackObjs[selector] || (delegateCallbackObjs[selector] = []);
  150. delegateCallbacks.push(callback);
  151. if (isAddEventListener) {
  152. var delegateFnArray = delegateFns[mid(element)];
  153. if (!delegateFnArray) {
  154. delegateFnArray = [];
  155. }
  156. var delegateCallback = delegateFn(element, event, selector, callback);
  157. delegateFnArray.push(delegateCallback);
  158. delegateCallback.i = delegateFnArray.length - 1;
  159. delegateCallback.type = event;
  160. delegateFns[mid(element)] = delegateFnArray;
  161. element.addEventListener(event, delegateCallback);
  162. if (event === 'tap') { //TODO 需要找个更好的解决方案
  163. element.addEventListener('click', function(e) {
  164. if (e.target) {
  165. var tagName = e.target.tagName;
  166. if (!preventDefaultException.test(tagName)) {
  167. if (tagName === 'A') {
  168. var href = e.target.href;
  169. if (!(href && ~href.indexOf('tel:'))) {
  170. e.preventDefault();
  171. }
  172. } else {
  173. e.preventDefault();
  174. }
  175. }
  176. }
  177. });
  178. }
  179. }
  180. });
  181. };
  182. $.fn.off = function(event, selector, callback) {
  183. return this.each(function() {
  184. var _mid = mid(this);
  185. if (!event) { //mui(selector).off();
  186. delegates[_mid] && delete delegates[_mid];
  187. } else if (!selector) { //mui(selector).off(event);
  188. delegates[_mid] && delete delegates[_mid][event];
  189. } else if (!callback) { //mui(selector).off(event,selector);
  190. delegates[_mid] && delegates[_mid][event] && delete delegates[_mid][event][selector];
  191. } else { //mui(selector).off(event,selector,callback);
  192. var delegateCallbacks = delegates[_mid] && delegates[_mid][event] && delegates[_mid][event][selector];
  193. $.each(delegateCallbacks, function(index, delegateCallback) {
  194. if (mid(delegateCallback) === mid(callback)) {
  195. delegateCallbacks.splice(index, 1);
  196. return false;
  197. }
  198. }, true);
  199. }
  200. if (delegates[_mid]) {
  201. //如果off掉了所有当前element的指定的event事件,则remove掉当前element的delegate回调
  202. if ((!delegates[_mid][event] || $.isEmptyObject(delegates[_mid][event]))) {
  203. findDelegateFn(this, event).forEach(function(fn) {
  204. this.removeEventListener(fn.type, fn);
  205. delete delegateFns[_mid][fn.i];
  206. }.bind(this));
  207. }
  208. } else {
  209. //如果delegates[_mid]已不存在,删除所有
  210. findDelegateFn(this).forEach(function(fn) {
  211. this.removeEventListener(fn.type, fn);
  212. delete delegateFns[_mid][fn.i];
  213. }.bind(this));
  214. }
  215. });
  216. };
  217. })(mui);