continue to look at jquery's typical event-based registration. Previously, jquery's management callback function relied on a top-level variable called Global. In jquery1.2.2 (this version is also an important version, with more than one hundred bugs fixed), the cache system was developed, this is also the jquery. data. The callback function is no longer stored on the elements. Instead, it makes an identifier for these elements to obtain these callback functions. After all, random addition of custom attributes to DOM elements is a hidden risk of Memory leakage and supports composite types (such as "Mouseover mouseout"). However, the biggest improvement is the correction of event objects.
Fix: function (event) {// when we call the Event Callback Function, we also need to perform cross-browser processing on our own. // when we call the event, this event is not the one that the browser gave us, but a common object // It copies all the members of the event object var originalevent = event; event = jquery. extend ({}, originalevent); // copy the member // Let IE also have preventdefault event. preventdefault = function () {// If preventdefault exists run it on the original event if (originalevent. preventdefault) originalevent. preventdefault (); // otherwise set the retur Nvalue property of the original event to false (IE) originalevent. returnvalue = false ;}; // Let IE also have stoppropagation event. stoppropagation = function () {// If stoppropagation exists run it on the original event if (originalevent. stoppropagation) originalevent. stoppropagation (); // otherwise set the cancelbubble property of the original event to true (IE) originalevent. cancelbubble = true;}; // Let IE also have Target, // Note: The document of IE does not have srcelement) if (! Event.tar get) event.tar get = event. srcelement | document; // fixes #1925 where srcelement might not be defined either // the safari text node is also the event source if (event.tar get. nodetype = 3) event.tar get = originalevent.tar get. parentnode; // Add relatedtarget, if necessary // make ie relatedtarget, but this attribute is also valid in the Mouseover and mouseout events in Firefox if (! Event. relatedtarget & event. fromelement) event. relatedtarget = event. fromelement = event.tar get? Event. toelement: event. fromelement; // calculate pagex/y if missing and clientx/y available // Add pagex/y to IE, but it is not accurate. 2px bug if (event. pagex = NULL & event. clientx! = NULL) {var Doc = document.doc umentelement, body = document. body; event. pagex = event. clientx + (Doc & Doc. scrollleft | Body & Body. scrollleft | 0)-(Doc. clientleft | 0); event. pagey = event. clienty + (Doc & Doc. scrolltop | Body & Body. scrolltop | 0)-(Doc. clienttop | 0);} // Add which for key events // Add which if (! Event. Which & (event. charcode | event. charcode = 0 )? Event. charcode: event. keycode) event. which = event. charcode | event. keycode; // Add metakey to non-Mac browsers (use ctrl for PC's and meta for Macs) if (! Event. metakey & event. ctrlkey) event. metakey = event. ctrlkey; // Add which for CLICK: 1 = left; 2 = middle; 3 = right // Note: button is not normalized, so don't use it // set the right-click in the left if (! Event. Which & event. Button) event. Which = (event. Button & 1? 1: (event. Button & 2? 3: (event. Button & 4? 2: 0); Return event ;},
Well, now let's look at the most popular version. It has made some improvements in the method of generating the fake event object. In two steps, we first use jquery. event generates an object, allowing it to obtain two W3C methods and a stop method, and then add attributes of interest to it.
Jquery. event. Add is used to add a callback function for an event of an element.
Jquery. event = {// Add the binding function Add: function (ELEM, types, handler, data) {// do not understand why text nodes are listed, if it is a comment node, It is the IF (ELEM. nodetype = 3 | ELEM. nodetype = 8) return; // process the window object, because the window has the setinterval method, but in the Multi-frame structure, such as El. contentWindow // el. frameelement, these El also have the setinterval method, but they are not the top-level window object if (ELEM. setinterval & ELEM! = Window) ELEM = Window; // assign a uuid if (! Handler. guid) handler. guid = This. guid ++; // if there is data, use proxy to wrapper it, And then attach data to it. // seriously suspect that data is a bubble parameter if (Data! = Undefined) {// create temporary function pointer to original handler var fn = handler; // create unique handler function, wrapped around original handler = This. proxy (FN); // store data in unique handler. data = data;} // init the element's event structure // according to the uuid of ELEM in jquery. set an events object var events = jquery. data (ELEM, "events") | jquery. data (ELEM, "Events", {}), // according to ele The UUID of M is in jquery. set a handle object in the cache and store a function into handle = jquery. data (ELEM, "handle") | jquery. data (ELEM, "handle", function () {// If event. triggered is true. Execute this function immediately, which is equivalent to IE's fireevent return typeof jquery! = "Undefined "&&! Jquery. event. triggered? // Arguments. callee. ELEM is handle. ELEM jquery. event. handle. apply (arguments. callee. ELEM, arguments): undefined;}); // Add ELEM as a property of the handle function // This is to prevent a memory leak with non-native // event in IE. handle. ELEM = ELEM; // handle multiple events separated by a space // jquery (...). BIND ("Mouseover mouseout", FN); // process two types of events at the same time, mainly used to simulate CSS: hover pseudo class jquery. each (types. split (// \ S +/), function (index, type) {// namespaced Event Handlers var namespaces = type. split (". "); type = namespaces. shift (); // equivalent to handler. type = "mouseout. mouseover "handler. type = namespaces. slice (). sort (). join (". "); // get the current list of functions bound to this event var handlers = events [type]; If (jquery. event. specialall [type]) jquery. event. specialall [type]. setup. call (ELEM, Data, namespaces ); // Init the event handler queue if (! Handlers) {handlers = events [type] = {}; // check for a special event handler // only use addeventlistener/attachevent if the special // events handler returns false // dom2 APIs are used only when domready is executed (other functions are available in the latest version) if (! Jquery. event. special [type] | jquery. event. special [type]. setup. call (ELEM, Data, namespaces) === false) {// bind the global event handler to the element if (ELEM. addeventlistener) ELEM. addeventlistener (type, handle, false); else if (ELEM. attachevent) ELEM. attachevent ("On" + type, handle) ;}// Add the function to the element's handler list handlers [handler. guid] = handler; // keep track of which events have been used, for global triggering jquery. event. global [type] = true;}); // nullify ELEM to prevent memory leaks in ie elem = NULL;}, guid: 1, Global :{},
jquery. event. Add applies to removing a specified callback function from an event of an element.
// Detach an event or set of events from an element remove: function (ELEM, types, Handler) {// don't do events on text and comment nodes if (ELEM. nodetype = 3 | ELEM. nodetype = 8) return; // obtain all event var events = jquery. data (ELEM, "events"), RET, index; If (events) {// unbind all events for the element if (types === undefined | (typeof types === "string" & types. charat (0) = ". ") (VAR type in events) // remove all types of events this. remove (ELEM, type + (types | ""); else {// types is actually an event object here if (types. type) {handler = types. handler; types = types. type;} // handle multiple events seperated by a space // jquery (...). unbind ("Mouseover mouseout", FN); jquery. each (types. split (/\ s +/), function (index, type) {// namespaced Event Handlers var namespaces = type. split (". "); Type = namespaces. shift (); var namespace = Regexp ("(^ | \\.) "+ namespaces. slice (). sort (). join (". *\\. ") + "(\\. | $) "); If (events [type]) {// remove a type // remove the given handler for the given type if (handler) // remove this callback function Delete events [type] [handler. guid]; // remove all handlers for the given type else for (VAR handle in events [type]) // handle the removal of namespaced events if (namespace. test (EV Ents [type] [handle]. type) delete events [type] [handle]; If (jquery. event. specialall [type]) jquery. event. specialall [type]. teardown. call (ELEM, namespaces); // remove generic event handler if no more handlers exist for (RET in events [type]) break; If (! RET) {If (! Jquery. event. special [type] | jquery. event. special [type]. teardown. call (ELEM, namespaces) ==== false) {If (ELEM. removeeventlistener) ELEM. removeeventlistener (type, jquery. data (ELEM, "handle"), false); else if (ELEM. detachevent) ELEM. detachevent ("On" + type, jquery. data (ELEM, "handle") ;}ret = NULL; Delete events [type] ;}}) ;} // remove the expando if it's no longer used for (RET in events) brea K; If (! RET) {// remove the relevant data on the group memory var handle = jquery. data (ELEM, "handle"); If (handle) handle. ELEM = NULL; jquery. removedata (ELEM, "events"); jquery. removedata (ELEM, "handle ");}}},
jquery. event. trigger allows you to program all the callback functions of an event type on a specified element, and to trigger more events of the same type on the Upper Layer Element Through event bubbling. Equivalent to IE fireevent
Trigger: function (event, Data, ELEM, bubbling) {// the event may have been transformed. // event object or event type var type = event. type | event; If (! Bubbling) {// if you cannot bubble up, // If the imported event is not a fake event object, convert it to a fake event = typeof event = "object "? // Jquery. event object event [expando]? Event: // if it is an event proxy, use type to initialize a counterfeit event object and inherit the attributes of the child element's counterfeit event object to jquery. extend (jquery. event (type), event): // just the event type (string) jquery. event (type); If (type. indexof ("! ")> = 0) {// determines whether the not operator exists. // The purpose is to execute a callback function event of another event type other than the input event type. type = type. slice (0,-1); event. exclusive = true;} // handle a global trigger if (! ELEM) {// don't bubble custom events when global (to avoid too much overhead) event. stoppropagation (); // prevents event bubbling because it is a bubble event object, so Ie can also call this method // only trigger if we 've ever bound an event for it if (this. global [type]) jquery. each (jquery. cache, function () {If (this. events & this. events [type]) jquery. event. trigger (event, Data, this. handle. ELEM);} // handle triggering a single element // don't do Eve ETS on text and comment nodes if (! ELEM | ELEM. nodetype = 3 | ELEM. nodetype = 8) return undefined; // clear the event. result, which is used to prevent event bubbling and the occurrence of default events. result = undefined; event.tar get = ELEM; // rewrite the event source object // clone the incoming data, if any data = jquery. makearray (data); data. unshift (event);} event. currenttarget = ELEM; // trigger the event, it is assumed that "handle" is a function var handle = jquery. data (ELEM, "handle"); If (handle) handle. Apply (ELEM, data); // handle triggering native. onfoo handlers (and on links since we don't call. click () for links) // process the click link. If the callback function return false, it cannot bubble up or execute the default behavior if ((! ELEM [type] | (jquery. nodename (ELEM, 'A') & type = "click") & ELEM ["on" + type] & ELEM ["on" + type]. apply (ELEM, data) ===false) event. result = false; // trigger the native events (Response t for clicks on links) // process events directly bound to the element if (! Bubbling & ELEM [type] &! Event. isdefaultprevented ()&&! (Jquery. nodename (ELEM, 'A') & type = "click") {This. triggered = true; try {ELEM [type] (); // prevent ie from throwing an error for some hidden elements} catch (e) {}} this. triggered = false; // Let it bubble to execute the same type of event on its ancestor element if (! Event. ispropagationstopped () {var parent = ELEM. parentnode | ELEM. ownerdocument; If (parent) jquery. event. trigger (event, Data, parent, true );}},
when a user clicks or moves a mouse on a page to trigger a callback function on an element, jquery modifies the callback function to process event objects, put the original event object or window. the event is enclosed in a counterfeit event object and passed in as the first parameter of the callback function.
Handle: function (event) {// returned undefined or false var all, handlers; // sets a fake event object, shielding the browser's differential event = arguments [0] = jquery. event. fix (event | window. event); event. currenttarget = This; // set the event execution object // namespaced Event Handlers var namespaces = event. type. split (". "); event. type = namespaces. shift (); // cache this now, all = true means, any handler all =! Namespaces. Length &&! Event. exclusive; var namespace = Regexp ("(^ | \\.) "+ namespaces. slice (). sort (). join (". *\\. ") + "(\\. | $) "); handlers = (jquery. data (this, "events") |{}) [event. type]; // obtain all callback functions of this type for (var j in handlers) {var handler = handlers [J]; // filter the functions by class if (all | namespace. test (handler. type) {// pass in a reference to the handler function itself // so that we can later remove it Eve NT. handler = handler; event. data = handler. data; // RET is used to determine whether to block bubble and execute the default behavior var ret = handler. apply (this, arguments); If (Ret! = Undefined) {event. result = ret; If (ret = false) {event. preventdefault (); event. stoppropagation () ;}}// used to prevent the event of the same type from executing if (event. isimmediatepropagationstopped () Break ;}}},
encapsulate the event object, wrap it with a common object, and make it have all the behaviors and attributes of the original event.
Props: "altkey attrchange attrname bubbles button cancelable charcode contains invalid currenttarget data detail eventphase fromelement handler keycode contains newvalue extends pagex Pagey prevvalue contains too many screeny limit srcelement target toelement view wheeldelta which ". split (""), fix: function (event) {// This function is used to generate fake event objects, shielding the differences between IE and W3C, see the previous if (event [Expand O]) return event; // store a copy of the original event object // and "clone" to set read-only properties var originalevent = event; event = jquery. event (originalevent); // Add Method for (VAR I = This. props. length, prop; I;) {// Add property prop = This. props [-- I]; event [prop] = originalevent [prop];} // fix target property, if necessary if (! Event.tar get) event.tar get = event. srcelement | document; // fixes #1925 where srcelement might not be defined either // check if target is a textnode (Safari) If (event.tar get. nodetype = 3) event.tar get = event.tar get. parentnode; // inaccurate. In ff, an error xui element if (! Event. relatedtarget & event. fromelement) event. relatedtarget = event. fromelement = event.tar get? Event. toelement: event. fromelement; // inaccurate. 2px bug if (event. pagex = NULL & event. clientx! = NULL) {var Doc = document.doc umentelement, body = document. body; event. pagex = event. clientx + (Doc & Doc. scrollleft | Body & Body. scrollleft | 0)-(Doc. clientleft | 0); event. pagey = event. clienty + (Doc & Doc. scrolltop | Body & Body. scrolltop | 0)-(Doc. clienttop | 0);} // Add which for key events if (! Event. Which & (event. charcode | event. charcode = 0 )? Event. charcode: event. keycode) event. which = event. charcode | event. keycode; // Add metakey to non-Mac browsers (use ctrl for PC's and meta for Macs) if (! Event. metakey & event. ctrlkey) event. metakey = event. ctrlkey; // Add which for CLICK: 1 = left; 2 = middle; 3 = right // Note: button is not normalized, so don't use it if (! Event. Which & event. Button) event. Which = (event. Button & 1? 1: (event. Button & 2? 3: (event. Button & 4? 2: 0); Return event ;},
I have not read more about other regions. Live seems to be used for event proxy.
Proxy: function (FN, proxy) {// generate a function proxy = proxy that wraps the original callback function | function () {return fn. apply (this, arguments) ;}; // set the guid of unique handler to the same of original handler, so it can be removed proxy. guid = fn. guid = fn. guid | proxy. guid | this. guid ++; // so proxy can be declared as an argument return proxy;}, Special: {// mainly used for domready ready: {// make sure the ready event is setup set Up: bindready, teardown: function () {}}, specialall: {live: {setup: function (selector, namespaces) {jquery. event. add (this, namespaces [0], livehandler) ;}, teardown: function (namespaces ){//??? Used for unload if (namespaces. length) {var remove = 0, name = Regexp ("(^ | \\.) "+ namespaces [0] + "(\\. | $) "); jquery. each (jquery. data (this, "events "). live | {}), function () {If (name. test (this. type) Remove ++;}); If (remove <1) jquery. event. remove (this, namespaces [0], livehandler );}}}}};