Analysis of event events in jquery source Analysis _jquery

Source: Internet
Author: User
Tags closure unique id uuid

The action for an event is nothing more than a addevent,fireevent,removeevent of these three event methods. General Lib will make some extensions to the functions provided by the browser to solve the problems such as compatibility memory leaks. The third question is how to get the Domready state.
Package of 6.1 Event

Browser event compatibility is a troubling issue. IE's event is under the Global window, and Mozilla's event is the incident source parameter passed into the callback function. There are also many ways to handle events.

jquery provides a package of event, which is a little simpler than the rest of Lib, but enough to use.

Copy Code code as follows:

Parcel out the event.
Fix:function (event) {
if (Event[expando] = = True) return event;//indicates that the event has been wrapped
Save the original event and clone one at the same time.
var originalevent = event; ①
event = {Originalevent:originalevent};
for (var i = this.props.length, prop;i;) {
Prop = This.props[--i];
Event[prop] = Originalevent[prop];
}
Event[expando] = true;
Plus preventdefault and stoppropagation, not running in clone
Event.preventdefault = function () {②
Run on the original event
if (Originalevent.preventdefault)
Originalevent.preventdefault ();
Originalevent.returnvalue = false;
};
Event.stoppropagation = function () {
Run on the original event
if (originalevent.stoppropagation)
Originalevent.stoppropagation ();
Originalevent.cancelbubble = true;
};
Fixed TimeStamp
Event.timestamp = Event.timestamp | | Now ();
Fixed target
if (!event.target) ③
Event.target = Event.srcelement | | Document
if (Event.target.nodeType = = 3)//Text node is the parent node.
Event.target = Event.target.parentNode;
Relatedtarget
if (!event.relatedtarget && event.fromelement) ④
Event.relatedtarget = Event.fromelement = = Event.target
? Event.toElement:event.fromElement;
Calculate pagex/y if missing and clientx/y available
if (Event.pagex = = null && event.clientx!= null) {⑥
var doc = document.documentelement, 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
if (!event.metakey && event.ctrlkey) ⑧
Event.metakey = Event.ctrlkey;
Add which for click:1 = = left; 2 = middle; 3 = Right
Note:button isn't 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;
},


The above code ① the original event's reference, while cloning the original event. Parcel on this clone event. ② on the original event run Preventdefault and stoppropagation two methods to prevent the default event action from occurring and whether to stop bubbling event events up-pass.

③ is fixed target, IE uses srcelement, and for text node events, Target should be uploaded to its parent node.

④ Place Relatedtarget only for mouseout, mouseover useful. In IE, the to and from two target variables are divided in Mozilla. In order to ensure compatibility, the use of Relatedtarget unified.

The ⑥ place is the coordinate position of the event. This is relative to page. If the page can be scroll, add scroll to its client. In IE, you should also subtract the default 2px body border.

The ⑦ place is the key to the keyboard event to unify the Event.which properties. Ext in the implementation of Ev.charcode | | Ev.keycode | | 0; ⑨ is the key to the mouse event to unify the Event.which on. CharCode, Ev.keycode One is a character key, a not a character key. The ⑨ department adopts the & method to handle the compatibility. EXT solves the compatibility issue by following three lines.

var btnmap = Ext.isie? {1:0,4:1,2:2}: (Ext.issafari?) {1:0,2:1,3:2}: {0:0,1:1,2:2}); This.button = E.button? Btnmap[e.button]: (E.which. E.which-1:-1);

①②③④⑤⑥⑦⑧⑨⑩

6.2 Handling of events

jquery provides a number of ways to do regist,remove,fire events.

6.2.1 Register

For registration events, jquery provides a method of four registration events for BIND, one, toggle, and hover, and bind is the most basic method. One is to register a method that runs only once, toggle the method of registering alternately. Hover is the method of registering mouse floating.
Copy Code code as follows:

Bind:function (type, data, fn) {
return type = = "Unload"? This.one (type, data, fn): this
. each (function () {//fn | | data, FN && data implements the data parameter optional
JQuery.event.add (this, type, fn | | data, fn && data);
}); },



In bind, the Unload event can only be run once, and the others are registered by default.

Bind a one-time event handler for each matching element's specific event (like click).
On each object, this event handler is only executed once. The other rules are the same as the bind () function.
This event handler receives an event object that can be used to block the default behavior of the (browser).
This event handler must return FALSE if you want to cancel the default behavior and prevent the event from bubbling.
Copy Code code as follows:

One:function (type, data, fn) {
var one = jQuery.event.proxy (fn | | data, function (event) {
JQuery (This). Unbind (event, one);
Return (fn | |-data). Apply (this, arguments);/this-> the current element
});
Return This.each (function () {
JQuery.event.add (this, type, one, FN && data);
});
},

One and bind are basically the same, different in the call JQuery.event.add, the registered event to handle the function of a small adjustment. One called JQuery.event.proxy to perform an agent incoming event handler function. When an event triggers a function that invokes this proxy, the event is removed from the cache before the registered event function is executed. Here is the closure of the application, through the closure of the FN registered event function reference.

A method that mimics a hover event (the mouse moves over an object and removes it).
This is a custom method that provides a "stay in" state for frequently used tasks.
When the mouse is moved above a matching element, the first specified function is triggered. When the mouse moves out of this element,
/triggers the specified second function. Also, it is accompanied by a detection of whether the mouse is still in a particular element (for example, an image in a div),
If so, the hover state is maintained without triggering the emigration event (fixed a common error using the Mouseout event).
Hover:function (Fnover, fnout) {
Return This.bind (' MouseEnter ', fnover). Bind (' MouseLeave ', fnout);
},



Hover is built on the basis of bind.

Call the function in turn after each click.
Toggle:function (FN) {
var args = arguments, i = 1;
while (I < args.length)//per function assign GUID
JQuery.event.proxy (FN, args[i++])/modified in Args
Return This.click (FN, function (event) {//Assign GUID This.lasttoggle = (This.lasttoggle | | 0)% i;//Previous letter Count Event.preventdefault ();//block Default action
Executes the first function in the parameter, apply can take the Array-like parameter
Return args[this.lasttoggle++].apply (this,arguments) | | False
}));
},

The toggle parameter can be multiple fn. First generate the UUID for their code. Then call the click Method to register the callback for the proxy again. This function runs when an event is triggered, and it evaluates to the last time the function in the parameter was executed. Then the default action is blocked. Then the next function is found to run.

Adding common event methods for jquery objects
Jquery.each (
("Blur,focus,load,resize,scroll,unload,click,dblclick,"
+ "Mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"
+ "Submit,keydown,keypress,keyup,error"). Split (","),
function (i, name) {Jquery.fn[name] = function (FN) {
RETURN FN? This.bind (Name, FN): This.trigger (name);
};});

jquery adds a common event-handling method that contains the click of the call above. Here you can see the call to bind for registration. Of course, this can also be achieved through the implementation of the program to trigger events.



Many of the above methods are registered events that eventually fall into the JQuery.event.add () to complete the registration function. If we adopt the DOM0 or DOM1 event method, we will use Elem.onclick=function () {} To register the handler function for one of the element's events. The biggest drawback of this is that each event is just a handler function. With improvements in the DOM1 approach, we can register multiple handler functions for an element's event with Elem.addeventlistener (type, handle, false).

This is not a perfect way to do this, but if we only run this event once it's a bit of a hassle. We're going to end up with Elem.removeeventlistener in the handler function of the event to cancel the interception of the event. Doing so may have problems with the transaction. What if the first event handler is triggered again without canceling the event listening?

There is also a browser approach, which does not support the registration and processing of custom events, and cannot register the same handler function for multiple events.
Copy Code code as follows:

Jquery.event = {//add event to an element.
Add:function (Elem, types, handler, data) {
if (Elem.nodetype = = 3 | | elem.nodetype = 8) return;//a blank node or comment
IE cannot pass in window, copy first.
if (JQuery.browser.msie && elem.setinterval) elem = window;
Assign a globally unique ID to the handler
if (!handler.guid) handler.guid = this.guid++;
Attach the data to the Handler.data
if (data!= undefined) {①
var fn = handler;
Handler =this.proxy (Fn,function () {return fn.apply (this,arguments);});
Handler.data = data;
}
Initializes the events of the element. If the value in events is not taken, initialize data: {}②
VAR events =jquery.data (Elem, "events") | | Jquery.data (Elem, "events", {}),
If the value in handle is not fetched, the data:function () {...} is initialized. ③
Handle = Jquery.data (Elem, "handle") | | Jquery.data (Elem, "handle"),
function () {///handle the second event of a trigger and call an event after the page has been unload.
if (typeof jQuery!= "undefined" &&!jquery.event.triggered)
Return JQuery.event.handle.apply (//callee.elem=handle.elem
Arguments.callee.elem, arguments);
});
Add Elem as the handle attribute to prevent IE leaking memory because there is no local event.
Handle.elem = Elem;
Processing uses a space to separate multiple event names, such as jquery (...). Bind ("MouseOver mouseout", FN);
Jquery.each (Types.split (/s+/), function (index, type) {④
namespace events, which are generally not used.
var parts = Type.split ("."); Type = Parts[0];handler.type = Parts[1];
All processing functions bundled to this element type event
var handlers = Events[type]; ⑤
if (!handlers) {//Initialize event queue without finding a list of handler functions
Handlers = Events[type] = {};
If type is not ready, or Ready's setup execution returns False⑥
if (!jquery.event.special[type]| | jquery.event.special[type].setup
. Call (elem, data) = = False) {//Calling the system's event function to register an event
if (Elem.addeventlistener) Elem.addeventlistener (Type,handle,false);
else if (elem.attachevent) elem.attachevent ("on" + type, handle);
}
}
Save the processor ID and handler form attribute pairs in the handlers list,
Also exists in Events[type][handler.guid].
Handlers[handler.guid] = handler; ⑦
Global cache usage Identity for this event
Jquery.event.global[type] = true;
});
  
Elem = null; Prevent IE memory leaks.
},
Guid:1,
Global: {},



JQuery.event.add the event name and handler function associated with the event by Jquery.data organically and orderly in the space corresponding to the element in Jquery.cache. Let's analyze the add process in one example: if we entertain jquery below (E1). bind ("MouseOver mouseout", fn0); jquery (E1). bind ("MouseOver mouseout", fn1) The statement.

In jquery (E1). bind ("MouseOver mouseout", fn0), ②③ can not be taken from the cache to the number, first initialized. CACHE:{E1_UUID:{EVENTS:{},HANDLE:FN}} at this time. The ⑤ is then initialized for the mouseover mouseout name. Cache at this time: {e1_uuid:{events:{mouseover:{}, MOUSEOUT:{}},HANDLE:FN}}. Registers the handler function with the browser's event at ⑥. Then ⑦ the handler function into the event name. Cache at this time: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{FN0_UUID:FN0}},HANDLE:FN}}. Here you can see the effect of using proxy as a function to generate a UUID.

In jquery (E1). bind ("MouseOver mouseout", fn1), ②③ is fetched from cache to data {e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ Fn0_uuid:fn0}}, and then ⑤ the reference to mouseover:{fn0_uuid:fn0},mouseout:{Fn0_uuid:fn0}. The ⑦ then registers the handler function in the event name. At this time the cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0, fn1_uuid:fn1,},mouseout:{fn0_uuid:fn0, Fn1_uuid:fn1}},handle : fn}}.

The important task of JQuery.event.add is to store the registered event functions in an orderly manner. So that the functions of the Remove and fire events can be found.

{ELEM_UUID_1:{EVENTS:{MOUSEOVER:{FN_UUID:FN1,FN_UUID1:FN2},
MOUSEOUT:{FN_UUID:FN1,FN_UUID1:FN2}},HANDLE:FN}}

6.2.2 Trigger



Registered an event, such as OnClick. When the user clicks on this element, the event's registered event handler is automatically triggered. But sometimes we have to use a program to simulate the triggering of an event to force an event to be triggered. In IE we can use. FireEvent () to implement. For example: <form onsubmit= "A ()" >, if the button form.submit () the way to submit the form, is not the initiative to trigger the Onsumbit event, if necessary, in the prior to submit $ (": Form") [0]. FireEvent ("onsubmit"), which triggers the event.

There are three steps in Mozilla: var evt = document.createevent (' htmlevents ');

Evt.initevent (' Change ', true,true); T.dispatchevent (EVT);

The prototype is implemented in this way. In jquery, the way it is implemented is a little different.
Copy Code code as follows:

Trigger:function (type, data, fn) {
Return This.each (function () {
JQuery.event.trigger (type, data, this, true, FN);
}); },

The trigger has three parameters, and the data parameter is a real pass for the registered event function. If preventdefault exists in data[0], data[0] can be used as a user-defined space for parcel events. FN can provide an instant, Ready-to-use event-handling method for events. That is, you can also handle events by passing in a handler function without registering an event. If it is already registered, it is executed after the original event handler function.

This method will trigger the handler function for all bindings on the specified event type. However, the browser default action is not performed.
Triggerhandler:function (type, data, fn) {
Return this[0]&& JQuery.event.trigger (TYPE,DATA,THIS[0],FALSE,FN);
},



Triggerhandle prevents the browser default from executing by setting the JQuery.event.trigger donative argument to False. What it does with trigger is that it's just the first element that handles the jquery object.

The above two methods call JQuery.event.trigger to complete the task:
Copy Code code as follows:

Trigger:function (type, data, Elem, donative, extra) {
data = Jquery.makearray (data);//data can be {xx:yy}
Support getdata! Such a form, exclusive = True performance will be registered for add
All functions of the event are executed by the type of the namespace.
if (Type.indexof ("!") >= 0) {①
Type = Type.slice (0,-1); var exclusive = true;
}
if (!elem) {//Handle Global Fire event ②
if (This.global[type])
Jquery.each (Jquery.cache, function () {
All elements registered for the event are found from the cache and the handler function that triggers the Change event
if (this.events && This.events[type])
JQuery.event.trigger (type, data, This.handle.elem);
});
} else {//fire event for individual element events ③
if (Elem.nodetype = = 3 | | elem.nodetype = 8) return undefined;
var val, ret, fn = jquery.isfunction (Elem[type] | | | null),
The event variable is true if the data parameter passes into the event object that is not a browser.
True if the data parameter itself is a Louboutin group, then the first element is not the browser's event object.
True for event. That is, there is no event entry, first building a forged event object exists data[0].
event =!data[0] | | !data[0].preventdefault;
Constructs a spoofed event object without passing in the event object.
if (event) {//Save to the first ④ in the array
Data.unshift ({Type:type,target:elem,
Preventdefault:function () {},stoppropagation:
function () {}, Timestamp:now ()});
Data[0][expando] = true; No need to fix a forged event object
}
Data[0].type = type; Prevent Event name Errors
The performance performs the classification (namespace) of the event registration function. Not all of them.
if (exclusive) data[0].exclusive = true;
  
Unlike prototype and other traditional treatment methods, not using FireEvent to
To fire the event handling method by registering to the browser event.
Here are three steps, first fire through the JQuery.event.add to register the event, this event
It could be a custom event (not registered in a browser event).
The second step is to fire the local processing function of events registered by the Elem.onclick method
The third step is to fire the default event handling mode (registered in the local onclick way)
Does not exist in the case).
This is the event that triggers the registration via JQuery.event.add.
var handle = Jquery.data (Elem, "handle"); ⑤
if (handle) Val = handle.apply (elem, data); Here data is divided into multiple parameters
Processing triggers a registered local processing method such as elem.onfoo=function (),
But for links ' s. Click () does not trigger, this does not execute through addevent
Way to register event handling.
if (!FN | | (Jquery.nodename (Elem, ' a ') && type = "click")) ⑥
&& elem[' on ' + type]&& elem[' on ' +type].apply (elem,data) = = False)
val = false;
The first few of the extra function parameters are given by data. This will remove the fake plus event.
Its last parameter is the result of a series of event-handler functions, typically a bool value
This function can be used to deal with a cleanup work based on this result.
if (event) Data.shift ();
Handles triggering extra given function processing.
if (extra && jquery.isfunction (extra)) {⑦
ret = Extra.apply (elem, val = = null Data:data.concat (val));
If this function has a return value, then the return value of the trigger is its return value
If not, the last return value of the concatenated event handler function. General for BOOL
if (ret!== undefined) val = ret;
}
Triggers the default local event method, which is registered in the absence of an event such as. onclick
This is done only if the previous execution event handler function returns a value that is not false.
It can also pass donative to control whether or not to execute.
As in form, you can use This.submit () to submit form.
if (FN && donative!== false && val!== False⑧
&&! (Jquery.nodename (Elem, ' a ') && type = "click")) {
This.triggered = true;
try {Elem[type] (); For some hidden elements, ie will make an error
catch (e) {}
}
This.triggered = false;
}
return Val;
},



jquery's Fire event approach is completely different from the prototype implementation. EXT, Yui does not provide a forced trigger event method. For general thinking, programs that trigger the browser's events should be run using FireEvent or Dispatchevent methods.

But jquery takes a different approach. For events registered through JQUERY.EVENT.ADD (whether customized or registered to browser events), it is stored in a cache corresponding to the element and event name. In the browser's trigger, this is of little effect. However, it is to get the corresponding event handler function from the cache when the trigger is forced by the program. This is the time to throw away the browser event. You can also perform some custom event functions here. such as ⑤ place.

An event function that is registered as a click or Elem.onclick=function () {} in the HTML label. At ⑥ it takes a callback function such as the onclick form of the execution element. Only one function can be registered in this dom0 way.

Sometimes, if you don't have an event handler like OnClick, the browser performs the default processing function. such as Form.submit (). ⑧ can be seen for this default event handling, but also through the parameter donative to control.

The program manually forces the event to be triggered, with one question being how the event is generated, or no browser generation event is passed into the function. Prototype takes the event of a newly generated dataavailable. Such events also have little effect. jquery also uses fake to forge an event, such as ④, which is more advantageous than the prototype event because it can pass the parameters of the trigger function to the required event. Prototype is not.

Through the above analysis, we can see that jquery is to build this trigger function by simulating the execution of the triggering event of the browser. Perform the event registered by the Dom1 method (Addevent), and then perform the event registered DOM0, and finally see if you want to perform the default event handling.

At ⑦, we can see that trigger may also pass the callback function and parameters to perform the processing of the result of the event handler function, and form a new result to return through the trigger function. This is useful in some cases.



In addition to these, it can classify the processing function of the event (namespace), and can invoke the different classification of the event's processing functions (registered by Jquery.event.add) at the appropriate time. The processing of this classification is implemented in handle.
Copy Code code as follows:

Handle:function (event) {
return undefined or false
var val, ret, namespace, all, handlers;
The parameters passed in were modified, and here is the reference.
event = Arguments[0] = JQuery.event.fix (Event | | window.event);
namespace processing
namespace = Event.type.split (".");
Event.type = namespace[0];
namespace = namespace[1];
All = True indicates that any handler,namespace does not exist, while
Event.exclusive does not exist or is false, all=true.
all =!namespace &&!event.exclusive;
List of handler functions for the cached event names found in events of the element
Handlers = (Jquery.data (This, "events") | | {}) [Event.type];
for (Var j in handlers) {//each handler function executes
var handler = Handlers[j];
Filter the functions by class
if (all | | handler.type = = namespace) {
Incoming references, in order to delete them later
Event.handler = handler;
Event.data = when Handler.data;//add was added
RET = handler.apply (this, arguments);//Execute event handler function
if (Val!== false)
val = ret;//This function returns false whenever one of the handler functions returns FALSE.
if (ret = false) {//Do not perform browser default action
Event.preventdefault ();
Event.stoppropagation ();
}
}
}
return Val; }

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.