好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

mass Framework event模块 v9

mass Framework event模块 v9

本次升级 借鉴了jQuery事件模块的许多代码,可谓是jQuery事件模块的改良版。

与原先一样,拆分为两块,event模块是支持新一代的浏览器的,如IE9,chrome5+, opera10+,safari5+;event_fix是对付IE678。

拆分后的好处,在标准浏览器中,我们就不要加载这么多代码,跑这么多注定要跳过的分支,有效地提升性能。

拆分后就有利于我对标准浏览器有一个新的了解,发现firefox成为最拖后腿的一位。它在滚轮事件,focusin, focusout的迟迟不合作,让我们不得不奠出eventSupport等利器。webkit系还需要模拟mouseenter, mouseleave事件。由于标准浏览器的原生属性不能被覆盖,比如我们用mouseover来冒充mouseenter,那么我们还得将它外包一层,这工作为$.Event来做。它本来就是用于摒蔽事件对象在各浏览器的差异性的,让IE也拥有W3C的调用接口。因此$.Event还是不能移到event_fix模块。

在jQuery中还有一个simulate方法,用于让事件对象伪装成另一类事件,根据最后一个参数在本层或整个DOM树中传播。但通过研读源码发现,它的最后参数总是true,并且它也多用于修复IE的事件派发,只有一处是用于FF。因此我把它放到event_fix中去了。

在$.event.fix方法中,我发现jQuery对原事件对象的属性复制是限死的,规定好了某些属性要被复制,因此伪事件对象在一些场合还是要访问originalEvent来干活。这里我做了一些改良。并且针对鼠标事件与键盘事件这两类事件的大补丁,我也分配好它们的归属。一个目标,减少无效的分支判定。jQuery在dispatch这个方法中实在做了许多判定了,因此跑得很慢,这会在一些持续触发的事件,如scroll, resize, mousemove等非常吃力。

即使在event模块中,事件系统还是要对一些事件进行特殊处理,分别是load, focus, blur, click, beforeunload。

再来看event_fix,只要是处理IE的事件代理,change与submit,还有就是事件对象对标准的跟随。这补丁模块总归要入土的,但现在它对大陆人来说还是必不可少。

事件模块是使用wrap方式进行,完全伪装原短对象在DOM的触发行为。许多神一样的代码是jQuery团队写的,偶只是照搬。另一些奇技淫巧虽然是我自创的,但给出足够的链接希望你们能看得懂。这一个框架最重要也是最复杂的一部分,许多框架的事件系统能搞成这样具够扩展性也极让人困惑。

event.js

View Code

//=========================================

// 事件系统 v9

//==========================================

define( "event" , top.dispatchEvent ? [ "$node" ] : [ "$event_fix" ], function ($) {

     var   facade = $.event || ($.event = {

         //对某种事件类型进行特殊处理

         special: {},

         //对Mouse事件这一大类事件类型的事件对象进行特殊处理

         fixMouse: function (event, real) {

             if (event.type === "mousewheel" ) { //处理滚轮事件

                 if ( "wheelDelta"   in   real) { //统一为±120,其中正数表示为向上滚动,负数表示向下滚动

                     // http://HdhCmsTestw3help.org/zh-cn/causes/SD9015

                     var   delta = real.wheelDelta

                     //opera 9x系列的滚动方向与IE保持一致,10后修正

                     if (window.opera && opera.version() < 10) delta = -delta;

                     event.wheelDelta = Math.round(delta); //修正safari的浮点 bug

                 } else   if ( "detail"   in   real) {

                     event.wheelDelta = -real.detail * 40; //修正FF的detail 为更大众化的wheelDelta

                 }

             }

         }

     }),

         eventHooks = facade.special,

         rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,

         rtypenamespace = /^([^.]*)(?:\.(.+)|)$/,

         mouseEvents = "contextmenu,click,dblclick,mouseout,mouseover,mouseenter,mouseleave,mousemove,mousedown,mouseup,mousewheel," ,

         eventMap = $.oneObject(mouseEvents, "Mouse" ),

         types = mouseEvents + ",keypress,keydown,keyup,"   + "blur,focus,focusin,focusout,"   + "abort,error,load,unload,resize,scroll,change,input,select,reset,submit"   //input

         $.eventSupport = function (eventName, el) {

             el = el || document.createElement( "div" );

             eventName = "on"   + eventName;

             var   ret = eventName in   el;

             if (el.setAttribute && !ret) {

                 el.setAttribute(eventName, "" );

                 ret = typeof   el[eventName] === "function" ;

                 el.removeAttribute(eventName);

             }

             el = null ;

             return   ret;

         };

 

     function   Event(src, props) {

         if (!( this   instanceof   $.Event)) {

             return   new   Event(src, props);

         }

         this .originalEvent = {}; //保存原生事件对象

         if (src && src.type) {

             this .originalEvent = src; //重写

             this .type = src.type;

         } else   {

             this .type = src;

         }

         this .defaultPrevented = false ;

         if (props) {

             $.mix( this , props);

         }

         this .timeStamp = new   Date - 0;

     };

     Event.prototype = {

         toString: function () {

             return   "[object Event]"

         },

         preventDefault: function () { //阻止默认行为

             this .defaultPrevented = true ;

             var   e = this .originalEvent

             if (e && e.preventDefault) {

                 e.preventDefault();

             }

             e.returnValue = false ;

             return   this ;

         },

         stopPropagation: function () { //阻止事件在DOM树中的传播

             var   e = this .originalEvent

             if (e && e.stopPropagation) {

                 e.stopPropagation();

             } //propagationStopped的命名出自 http://opera.im/kb/userjs/

             e.cancelBubble = this .propagationStopped = true ;

             return   this ;

         },

         stopImmediatePropagation: function () { //阻止事件在一个元素的同种事件的回调中传播

             this .isImmediatePropagationStopped = true ;

             this .stopPropagation();

             return   this ;

         }

     }

     $.Event = Event;

     $.mix(eventHooks, {

         load: { //此事件不能冒泡

             noBubble: true

         },

         click: { //处理checkbox中的点击事件

             trigger: function () {

                 if ( this .nodeName == "INPUT"   && this .type === "checkbox"   && this .click) {

                     this .click();

                     return   false ;

                 }

             }

         },

         focus: { //IE9-在不能聚焦到隐藏元素上,强制触发此事件会抛错

             trigger: function () {

                 if ( this   !== document.activeElement && this .focus) {

 

                     try   {

                         this .focus();

                         return   false ;

                     } catch (e) {}

                 }

             },

             delegateType: "focusin"

         },

         blur: {

             trigger: function () { //blur事件的派发使用原生方法实现

                 if ( this   === document.activeElement && this .blur) {

                     this .blur();

                     return   false ;

                 }

             },

             delegateType: "focusout"

         },

         beforeunload: {

             postDispatch: function (event) {

                 if (event.result !== void 0) {

                     event.originalEvent.returnValue = event.result;

                 }

             }

         }

     });

 

     $.mix(facade, {

         //addEventListner API的支持情况:chrome 1+ FF1.6+ IE9+ opera 7+ safari 1+;

         // http://functionsource测试数据/post/addeventlistener-all-the-way-back-to-ie-6

         add: function (elem, hash) {

             var   elemData = $._data(elem),

                 //取得对应的缓存体

                 types = hash.type,

                 //原有的事件类型,可能是复数个

                 selector = hash.selector,

                 //是否使用事件代理

                 handler = hash.handler; //回调函数

             if (elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler) {

                 return ;

             }

             hash.uniqueNumber = $.getUid(handler); //确保hash.uuid与fn.uuid一致

             var   events = elemData.events || (elemData.events = []),

                 eventHandle = elemData.handle;

             if (!eventHandle) {

                 elemData.handle = eventHandle = function (e) {

                     return   typeof   $ !== "undefined"   && (!e || facade.triggered !== e.type) ? facade.dispatch.apply(eventHandle.elem, arguments) : void 0;

                 };

                 eventHandle.elem = elem; //由于IE的attachEvent回调中的this不指向绑定元素,需要强制缓存它

             }

 

             types.replace($.rword, function (t) {

                 var   tns = rtypenamespace.exec(t) || [],

                     type = tns[1];

                 var   namespaces = (tns[2] || "" ).split( "." ).sort();

                 // 看需不需要特殊处理

                 var   hook = eventHooks[type] || {};

                 // 事件代理与事件绑定可以使用不同的冒充事件

                 type = (selector ? hook.delegateType : hook.bindType) || type;

                 hook = eventHooks[type] || {};

                 var   handleObj = $.mix({}, hash, {

                     type: type,

                     origType: tns[1],

                     namespace: namespaces.join( "." )

                 });

 

                 var   handlers = events[type]; //初始化事件列队

                 if (!handlers) {

                     handlers = events[type] = [];

                     handlers.delegateCount = 0;

                     if (!hook.setup || hook.setup.call(elem, namespaces, eventHandle) === false ) {

                         if ($[ "@bind" ] in   elem) {

                             $.bind(elem, type, eventHandle)

                         }

                     }

                 }

                 if (hook.add) {

                     hook.add.call(elem, handleObj);

                 }

                 //先处理用事件代理的回调,再处理用普通方式绑定的回调

                 if (selector) {

                     handlers.splice(handlers.delegateCount++, 0, handleObj);

                 } else   {

                     handlers.push(handleObj);

                 }

                 //用于优化fire方法

                 facade.global[type] = true ;

             })

             //防止IE内在泄漏

             elem = null ;

         },

         //用于优化事件派发

         global: {},

         //移除目标元素绑定的回调

         remove: function (elem, hash) {

             var   elemData = $._data(elem),

                 events, origType

             if (!(events = elemData.events)) return ;

 

             var   types = hash.type || "" ,

                 selector = hash.selector,

                 handler = hash.handler;

             types.replace($.rword, function (t) {

                 var   tns = rtypenamespace.exec(t) || [],

                     type = origType = tns[1],

                     namespaces = tns[2];

                 //只传入命名空间,不传入事件类型,则尝试遍历所有事件类型

                 if (!type) {

                     for (type in   events) {

                         facade.unbind(elem, $.mix({}, hash, {

                             type: type + t

                         }));

                     }

                     return

                 }

                 var   hook = eventHooks[type] || {};

                 type = (selector ? hook.delegateType : hook.bindType) || type;

                 var   handlers = events[type] || [];

                 var   origCount = handlers.length;

                 namespaces = namespaces ? new   RegExp( "(^|\\.)"   + namespaces.split( "." ).sort().join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : null ;

 

                 for ( var   j = 0, handleObj; j < handlers.length; j++) {

                     handleObj = handlers[j];

                     //如果事件类型相同,回调相同,命名空间相同,选择器相同则移除此handleObj

                     if ((origType === handleObj.origType) && (!handler || handler.uniqueNumber === handleObj.uniqueNumber) && (!namespaces || namespaces.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**"   && handleObj.selector)) {

                         handlers.splice(j--, 1);

 

                         if (handleObj.selector) {

                             handlers.delegateCount--;

                         }

                         if (hook.remove) {

                             hook.remove.call(elem, handleObj);

                         }

                     }

                 }

 

                 if (handlers.length === 0 && origCount !== handlers.length) {

                     if (!hook.teardown || hook.teardown.call(elem, namespaces, elemData.handle) === false ) {

                         if ($[ "@bind" ] in   elem) {

                             $.unbind(elem, type, elemData.handle)

                         }

                     }

 

                     delete   events[type];

                 }

             })

 

             if ($.isEmptyObject(events)) {

                 delete   elemData.handle;

                 $._removeData(elem, "events" ); //这里会尝试移除缓存体

             }

         },

         //通过传入事件类型或事件对象,触发事件回调,在整个DOM树中执行

         trigger: function (event) {

             var   elem = this ;

             //跳过文本节点与注释节点,主要是照顾旧式IE

             if (elem && (elem.nodeType === 3 || elem.nodeType === 8)) {

                 return ;

             }

 

             var   i, cur, old, ontype, handle, eventPath, bubbleType, type = event.type || event,

                 namespaces = event.namespace ? event.namespace.split( "." ) : [];

 

             // focus/blur morphs to focusin/out; ensure we're not firing them right now

             if (rfocusMorph.test(type + facade.triggered)) {

                 return ;

             }

 

             if (type.indexOf( "." ) >= 0) {

                 //分解出命名空间

                 namespaces = type.split( "." );

                 type = namespaces.shift();

                 namespaces.sort();

             }

             //如果从来没有绑定过此种事件,也不用继续执行了

             if (!elem && !facade.global[type]) {

                 return ;

             }

 

             // Caller can pass in an Event, Object, or just an event type string

             event = typeof   event === "object"   ?

             // 如果是$.Event实例

             event.originalEvent ? event :

             // Object literal

             new   $.Event(type, event) :

             // Just the event type (string)

             new   $.Event(type);

 

             event.type = type;

             event.isTrigger = true ;

             event.namespace = namespaces.join( "." );

             event.namespace_re = event.namespace ? new   RegExp( "(^|\\.)"   + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : null ;

             ontype = type.indexOf( ":" ) < 0 ? "on"   + type : "" ;

             //清除result,方便重用

             event.result = void 0;

             if (!event.target) {

                 event.target = elem;

             }

             //取得额外的参数

             var   data = $.slice(arguments);

             data[0] = event;

             //判定是否需要用到事件冒充

             var   hook = eventHooks[type] || {};

             if (hook.trigger && hook.trigger.apply(elem, data) === false ) {

                 return ;

             }

 

             //铺设往上冒泡的路径,每小段都包括处理对象与事件类型

             eventPath = [

                 [elem, hook.bindType || type]

             ];

             if (!hook.noBubble && !$.type(elem, "Window" )) {

 

                 bubbleType = hook.delegateType || type;

                 cur = rfocusMorph.test(bubbleType + type) ? elem : elem.parentNode;

                 for (old = elem; cur; cur = cur.parentNode) {

                     eventPath.push([cur, bubbleType]);

                     old = cur;

                 }

                 //一直冒泡到window

                 if (old === (elem.ownerDocument || document)) {

                     eventPath.push([old.defaultView || old.parentWindow || window, bubbleType]);

                 }

             }

 

             //沿着之前铺好的路触发事件

             for (i = 0; i < eventPath.length && !event.propagationStopped; i++) {

 

                 cur = eventPath[i][0];

                 event.type = eventPath[i][1];

 

                 handle = ($._data(cur, "events" ) || {})[event.type] && $._data(cur, "handle" );

                 if (handle) {

                     handle.apply(cur, data);

                 }

                 //处理直接写在标签中的内联事件或DOM0事件

                 handle = ontype && cur[ontype];

                 if (handle && handle.apply && handle.apply(cur, data) === false ) {

                     event.preventDefault();

                 }

             }

             event.type = type;

             //如果没有阻止默认行为

             if (!event.defaultPrevented) {

 

                 if ((!hook._default || hook._default.apply(elem.ownerDocument, data) === false ) && !(type === "click"   && elem.nodeName == "A" )) {

                     if (ontype && $.isFunction(elem[type]) && elem.nodeType) {

 

                         old = elem[ontype];

 

                         if (old) {

                             elem[ontype] = null ;

                         }

                         //防止二次trigger,elem.click会再次触发addEventListener中绑定的事件

                         facade.triggered = type;

                         try   {

                             //IE6-8在触发隐藏元素的focus/blur事件时会抛出异常

                             elem[type]();

                         } catch (e) {}

                         delete   facade.triggered;

 

                         if (old) {

                             elem[ontype] = old;

                         }

                     }

                 }

             }

 

             return   event.result;

         },

         //执行用户回调,只在当前元素中执行

         dispatch: function (e) {

             //如果不存在事件回调就没有必要继续进行下去

             var   eventType = e.type,

                 handlers = (($._data( this , "events" ) || {})[eventType] || [])

                 if (!handlers.length) {

                     return ;

                 }

                 //摒蔽事件对象在各浏览器下的差异性

             var   event = $.event.fix(e),

                 delegateCount = handlers.delegateCount,

                 args = $.slice(arguments),

                 hook = eventHooks[eventType] || {},

                 handlerQueue = [],

                 ret, selMatch, matched, matches, handleObj, sel

                 //重置第一个参数

                 args[0] = event;

             event.delegateTarget = this ;

 

             // 经典的AOP模式

             if (hook.preDispatch && hook.preDispatch.call( this , event) === false ) {

                 return ;

             }

             //收集阶段

             //如果使用了事件代理,则先执行事件代理的回调, FF的右键会触发点击事件,与标签不符

             if (delegateCount && !(event.button && eventType === "click" )) {

                 for ( var   cur = event.target; cur != this ; cur = cur.parentNode || this ) {

                     //disabled元素不能触发点击事件

                     if (cur.disabled !== true   || eventType !== "click" ) {

                         selMatch = {};

                         matches = [];

                         for ( var   i = 0; i < delegateCount; i++) {

                             handleObj = handlers[i];

                             sel = handleObj.selector;

                             //判定目标元素(this)的孩子(cur)是否匹配(sel)

                             if (selMatch[sel] === void 0) {

                                 selMatch[sel] = $(sel, this ).index(cur) >= 0

                             }

                             if (selMatch[sel]) {

                                 matches.push(handleObj);

                             }

                         }

                         if (matches.length) {

                             handlerQueue.push({

                                 elem: cur,

                                 matches: matches

                             });

                         }

                     }

                 }

             }

 

             // 这是事件绑定的回调

             if (handlers.length > delegateCount) {

                 handlerQueue.push({

                     elem: this ,

                     matches: handlers.slice(delegateCount)

                 });

             }

 

             // 如果没有阻止事件传播,则执行它们

             for (i = 0; i < handlerQueue.length && !event.propagationStopped; i++) {

                 matched = handlerQueue[i];

                 event.currentTarget = matched.elem;

                 for ( var   j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped; j++) {

                     handleObj = matched.matches[j];

                     //namespace,.namespace_re属性只出现在trigger方法中

                     if (!event.namespace || event.namespace_re && event.namespace_re.test(handleObj.namespace)) {

 

                         event.data = handleObj.data;

                         event.handleObj = handleObj;

                         ret = ((eventHooks[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args);

                         handleObj.times--;

                         if (handleObj.times === 0) { //如果有次数限制并到用光所有次数,则移除它

                             facade.unbind(matched.elem, handleObj)

                         }

                         if (ret !== void 0) {

                             event.result = ret;

                             if (ret === false ) {

                                 event.preventDefault();

                                 event.stopPropagation();

                             }

                         }

                     }

                 }

             }

 

             if (hook.postDispatch) {

                 hook.postDispatch.call( this , event);

             }

 

             return   event.result;

         },

 

         //修正事件对象,摒蔽差异性

         fix: function (event) {

             if (!event.originalEvent) {

                 var   real = event;

                 event = $.Event(real);

                 //复制真实事件对象的成员

                 for ( var   p in   real) {

                     if (!(p in   event)) {

                         event[p] = real[p]

                     }

                 }

                 //如果不存在target属性,为它添加一个

                 if (!event.target) {

                     event.target = event.srcElement || document;

                 }

                 //safari的事件源对象可能为文本节点,应代入其父节点

                 if (event.target.nodeType === 3) {

                     event.target = event.target.parentNode;

                 }

                 event.metaKey = !! event.ctrlKey; // 处理IE678的组合键

                 var   callback = facade[ "fix"   + eventMap[event.type]]

                 if ( typeof   callback == "function" ) {

                     callback(event, real)

                 }

             }

             return   event;

         }

     });

     facade.bind = facade.add;

     facade.unbind = facade.remove;

     //以下是用户使用的API

     $.implement({

         hover: function (fnIn, fnOut) {

             return   this .mouseenter(fnIn).mouseleave(fnOut || fnIn);

         },

         delegate: function (selector, types, fn, times) {

             return   this .on(types, selector, fn, times);

         },

         live: function (types, fn, times) {

             $.log( "$.fn.live() is deprecated" )

             $( this .ownerDocument).on(types, this .selector, fn, times);

             return   this ;

         },

         one: function (types, fn) {

             return   this .on(types, fn, 1);

         },

         undelegate: function (selector, types, fn) { /*顺序不能乱*/

             return   arguments.length == 1 ? this .off(selector, "**" ) : this .off(types, fn, selector);

         },

         die: function (types, fn) {

             $.log( "$.fn.die() is deprecated" )

             $( this .ownerDocument).off(types, fn, this .selector || "**" , fn);

             return   this ;

         },

         fire: function () {

             var   args = arguments;

             return   this .each( function () {

                 facade.trigger.apply( this , args);

             });

         }

     });

     //这个迭代器产生四个重要的事件绑定API on off bind unbind

     var   rtypes = /^[a-z0-9_\-\.\s\,]+$/i

     "on_bind,off_unbind" .replace($.rmapper, function (_, method, mapper) {

         $.fn[method] = function (types, selector, fn) {

             if ( typeof   types === "object" ) {

                 for ( var   type in   types) {

                     $.fn[method]( this , type, selector, types[type], fn);

                 }

                 return   this ;

             }

             var   hash = {};

             for ( var   i = 0; i < arguments.length; i++) {

                 var   el = arguments[i];

                 if ( typeof   el == "number" ) {

                     hash.times = el;

                 } else   if ( typeof   el == "function" ) {

                     hash.handler = el

                 }

                 if ( typeof   el === "string" ) {

                     if (hash.type != null ) {

                         hash.selector = el.trim();

                     } else   {

                         hash.type = el.trim(); //只能为字母数字-_.空格

                         if (!rtypes.test(hash.type)) {

                             throw   new   Error( "事件类型格式不正确" )

                         }

                     }

                 }

             }

             if (!hash.type) {

                 throw   new   Error( "必须指明事件类型" )

             }

             if (method === "on"   && !hash.handler) {

                 throw   new   Error( "必须指明事件回调" )

             }

             hash.times = hash.times > 0 ? hash.times : Infinity;

             return   this .each( function () {

                 facade[mapper]( this , hash);

             });

         }

         $.fn[mapper] = function () { // $.fn.bind $.fn.unbind

             return   $.fn[method].apply( this , arguments);

         }

     });

 

     types.replace($.rword, function (type) { //这里产生以事件名命名的快捷方法

         eventMap[type] = eventMap[type] || (/key/.test(type) ? "Keyboard"   : "HTML" )

         $.fn[type] = function (callback) {

             return   callback ? this .bind(type, callback) : this .fire(type);

         }

     });

     /* mouseenter/mouseleave/focusin/focusout已为标准事件,经测试IE5+,opera11,FF10+都支持它们

详见 http://HdhCmsTestfilehippo测试数据/pl/download_opera/changelog/9476/

          */

     if (!+ "\v1"   || !$.eventSupport( "mouseenter" )) { //IE6789不能实现捕获与safari chrome不支持

         "mouseenter_mouseover,mouseleave_mouseout" .replace($.rmapper, function (_, type, fix) {

             eventHooks[type] = {

                 delegateType: fix,

                 bindType: fix,

                 handle: function (event) {

                     var   ret, target = this ,

                         related = event.relatedTarget,

                         handleObj = event.handleObj;

                     // For mousenter/leave call the handler if related is outside the target.

                     // NB: No relatedTarget if the mouse left/entered the browser window

                     if (!related || (related !== target && !$.contains(target, related))) {

                         event.type = handleObj.origType;

                         ret = handleObj.handler.apply( this , arguments);

                         event.type = fix;

                     }

                     return   ret;

                 }

             }

         });

     }

     //现在只有firefox不支持focusin,focusout事件,并且它也不支持DOMFocusIn,DOMFocusOut,不能像DOMMouseScroll那样简单冒充,Firefox 17+

     if (!$.support.focusin) {

         "focusin_focus,focusout_blur" .replace($.rmapper, function (_, orig, fix) {

             var   attaches = 0,

                 handler = function (event) {

                     event = facade.fix(event);

                     $.mix(event, {

                         type: orig,

                         isSimulated: true

                     });

                     facade.trigger.call(event.target, event);

                 };

             eventHooks[orig] = {

                 setup: function () {

                     if (attaches++ === 0) {

                         document.addEventListener(fix, handler, true );

                     }

                 },

                 teardown: function () {

                     if (--attaches === 0) {

                         document.removeEventListener(fix, handler, true );

                     }

                 }

             };

         });

     }

     try   {

         //FF需要用DOMMouseScroll事件模拟mousewheel事件

         document.createEvent( "MouseScrollEvents" );

         eventHooks.mousewheel = {

             bindType: "DOMMouseScroll" ,

             delegateType: "DOMMouseScroll"

         }

         if ($.eventSupport( "mousewheel" )) {

             delete   eventHooks.mousewheel;

         }

     } catch (e) {};

 

     return   $;

})

event_fix.js

View Code

define( "event_fix" , !! document.dispatchEvent, [ "$node" ], function ($) {

     //模拟IE678的reset,submit,change的事件代理

     var   rformElems = /^(?:input|select|textarea)$/i

     var   facade = $.event = {

         special: {},

         fixMouse: function (event) {

             // 处理鼠标事件 http://HdhCmsTestw3help.org/zh-cn/causes/BX9008

             var   doc = event.target.ownerDocument || document; //safari与chrome下,滚动条,视窗相关的东西是放在body上

             var   box = document测试数据patMode == "BackCompat"   ? doc.body : doc.documentElement

             event.pageX = event.clientX + (box.scrollLeft >> 0) - (box.clientLeft >> 0);

             event.pageY = event.clientY + (box.scrollTop >> 0) - (box.clientTop >> 0);

             //如果不存在relatedTarget属性,为它添加一个

             if (!event.relatedTarget && event.fromElement) { //mouseover mouseout

                 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;

             }

             //标准浏览判定按下鼠标哪个键,左1中2右3

             var   button = event.button

             //IE event.button的意义 0:没有键被按下 1:按下左键 2:按下右键 3:左键与右键同时被按下 4:按下中键 5:左键与中键同时被按下 6:中键与右键同时被按下 7:三个键同时被按下

             event.which = [0, 1, 3, 0, 2, 0, 0, 0][button]; //0现在代表没有意义

         },

         fixKeyboard: function (event) {

             event.which = event.charCode != null   ? event.charCode : event.keyCode;

         }

     };

     var   special = facade.special

 

     function   simulate(type, elem, event) {

         event = new   $.Event(event);

         $.mix({

             type: type,

             isSimulated: true

         });

         $.event.trigger.call(elem, event);

         if (event.defaultPrevented) {

             event.preventDefault();

         }

     }

     special.change = {

         setup: function () {

             if (rformElems.test( this .nodeName)) {

                 // IE doesn't fire change on a check/radio until blur; trigger it on click

                 // after a propertychange. Eat the blur-change in special.change.handle.

                 // This still fires onchange a second time for check/radio after blur.

                 if ( this .type === "checkbox"   || this .type === "radio" ) {

                     $( this ).bind( "propertychange._change" , function (event) {

                         if (event.originalEvent.propertyName === "checked" ) {

                             this ._just_changed = true ;

                         }

                     });

                     $( this ).bind( "click._change" , function (event) {

                         if ( this ._just_changed && !event.isTrigger) {

                             this ._just_changed = false ;

                         }

                         // Allow triggered, simulated change events (#11500)

                         simulate( "change" , this , event);

                     });

                 }

                 return   false ;

             }

             // Delegated event; lazy-add a change handler on descendant inputs

             $( this ).bind( "beforeactivate._change" , function (e) {

                 var   elem = e.target;

                 if (rformElems.test(elem.nodeName) && !$._data(elem, "_change_attached" )) {

                     $(elem).bind( "change._change" , function (event) {

                         if ( this .parentNode && !event.isSimulated && !event.isTrigger) {

                             simulate( "change" , this .parentNode, event);

                         }

                         $._data(elem, "_change_attached" , true );

                     })

                 }

             });

         },

         handle: function (event) {

             var   elem = event.target;

             // Swallow native change events from checkbox/radio, we already triggered them above

             if ( this   !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio"   && elem.type !== "checkbox" )) {

                 return   event.handleObj.handler.apply( this , arguments);

             }

         },

         teardown: function () {

             facade.remove( this , "._change" );

             return   !rformElems.test( this .nodeName);

         }

     }

     special.submit = {

         setup: function () {

             // Only need this for delegated form submit events

             if ( this .tagName === "FORM" ) {

                 return   false ;

             }

             // Lazy-add a submit handler when a descendant form may potentially be submitted

             $( this ).bind( "click._submit keypress._submit" , function (e) {

                 // Node name check avoids a VML-related crash in IE (#9807)

                 var   elem = e.target,

                 form = /input|button/i.test(elem.tagName) ? elem.form : undefined;

                 if (form && !$._data(form, "_submit_attached" )) {

                     facade.bind(form, {

                         type: "submit._submit" ,

                         callback: function (event) {

                             event._submit_bubble = true ;

                         }

                     });

                     $._data(form, "_submit_attached" , true );

                 }

             });

         // return undefined since we don't need an event listener

         },

 

         postDispatch: function (event) {

             // If form was submitted by the user, bubble the event up the tree

             if (event._submit_bubble) {

                 delete   event._submit_bubble;

                 if ( this .parentNode && !event.isTrigger) {

                     simulate( "submit" , this .parentNode, event);

                 }

             }

         },

 

         teardown: function () {

             if ( this .tagName == "FORM" ) {

                 return   false ;

             }

             facade.remove( this , "._submit" );

         }

     }

     return   $;

})

 

 

 

标签:  javascript ,  mass

作者: Leo_wl

    

出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于mass Framework event模块 v9的详细内容...

  阅读:87次