Simple analysis of jquery binding principle and implementation of code sharing _jquery

Source: Internet
Author: User
Tags setinterval uuid delete cache
JQ has a method of data that binds the DOM elements to the relevant information. When an event is bound to the DOM using a JQ method, a corresponding time list is generated
See the example below (see Firefox for object Support Tosource ())
Copy Code code as follows:

<! DOCTYPE html>
<meta http-equiv= "Content-type" content= "text/html; charset=gb2312 "/>
<title></title>
<body>
<div id= "Test" ></div>
<script type= "Text/javascript" src= "Http://common.cnblogs.com/script/jquery.js" ></script>
<script type= "Text/javascript" >
Window.onload = function () {
Alert ($.data (' #test ') [0], ' events ');//null
Alert ($.data (' #test ') [0], ' handle ');//null
$ (' #test ')
. bind (' click ', function () {
Alert (1)
})
. bind (' MouseOver ', function () {
Alert (2)
})
. bind (' click ', function () {
Alert (3)
})
. bind (' click ', function () {
Alert (4)
})
Alert ($.data (' #test ') [0], ' events '). Tosource ());//Time list
Alert ($.data (' #test ') [0], ' handle '). Tosource ())//function executed
}
</script>
</body>

Data is an element that binds to the
The data source is the cache object
When the element binds the data, an attribute is added to the element jqueryxxx xxx is the timestamp of the execution JQ
Here's to say, there's a uuid, he's cumulative.
Jqueryxxx's value is this UUID.
The cache key is this UUID.
Value is the data to be saved
Data is important for the binding of events ..... ........... .........
Copy Code code as follows:

function Now () {
return +new Date;
};
var win = this,
expando = "JQuery" + Now (),
UUID = 0,
cache = {};
Win.data = function (elem, name, data) {
var id = Elem[expando];
if (!id)
id = Elem[expando] = ++uuid;
if (Name&&!cache[id])
Cache[id] = {};
if (data!== undefined)
Cache[id][name] = data;
return name
? Cache[id][name]
: ID;
}
Win.removedata = function (elem, name) {
var id = Elem[expando];
if (name) {
if (Cache[id]) {
Delete Cache[id][name];
name = "";
for (name in cache[ID])
Break
if (!name)
Removedata (Elem);
}
}else{
try {
Delete Elem[expando];
catch (e) {
if (Elem.removeattribute)
Elem.removeattribute (expando);
}
Delete Cache[id];
}
}
Win.each = function (object, callback, args) {
var name, i = 0, length = object.length;
if (args) {
if (length = = undefined) {
For (name in object)
if (callback.apply (object[name], args) = = False)
Break
} else
for (; i < length;)
if (callback.apply (object[i++], args) = = False)
Break
} else {
if (length = = undefined) {
For (name in object)
if (Callback.call (object[name, name, object[name]) = = False)
Break
} else
for (var value = object[0];
I < length && Callback.call (value, I, value)!== false; Value = Object[++i]) {}
}
return object;
}

Then implement Add event
JQ inside is the Add method inside the Jquery.event
Some features are implemented in the Add method
Take the events,handle of the element, these 2 data bindings
Events are stored in the event list
Format is as follows
{
Click: [{handler:function () {},type: ' click ', GUID: ' xx '} ...],
Mouse:[...]
}
Handle is a function of execution
(All the execution functions are the same they traverse the list of events to perform the corresponding events)
Then traverse types because you can bind multiple events
The callback function also gives several properties
Suppose the callback function is handler
Handler.guid = gevent.guid++
Handler.type = Name
Name should be counted as a special name for easy deletion
Like what
$ (' #xx ')
. bind (' click ', Function () {})
. bind (' click.d ', handler)
Name is D.
Delete When you can delete only D that event does not delete the above click event
The last is to bind the event to the element, but the function to execute is
function () {
Gevent.handle.apply (Arguments.callee.elem, arguments);
});
Copy Code code as follows:

Win.gevent = {
Guid:1,
Add:function (Elem, types, handler) {
if (Elem.nodetype = 3 | | elem.nodetype = 8)
Return
if (elem.setinterval && elem!= window)
Elem = window;
An index that uniquely identifies a function makes it easier to delete the event later
if (!HANDLER.GUID)
Handler.guid = this.guid++;
Get the data under the events handle of the element
var events = data (Elem, "events") | | Data (Elem, "events", {}),
Handle =data (Elem, "handle") | | Data (Elem, "Handle", function () {
Gevent.handle is the function that is executed after various actions are triggered.
Gevent.handle.apply (Arguments.callee.elem, arguments);
});
Handle.elem = Elem;
Traverse event name because it can be click MouseOver
Each (Types.split (/\s+/), function (index, type) {
var namespaces = Type.split (".");
Get Event name
Type = Namespaces.shift ();
The thing behind the dot is a special name. You can specify the deletion when you delete him like CLICK.D
Record this particular name with the type of event
Handler.type = Namespaces.slice (). Sort (). Join (".");
To obtain whether the event already exists in this object.
var handlers = Events[type];
If the event does not exist for the element to bind the event
if (!handlers) {
Handlers = Events[type] = {};
if (Elem.addeventlistener)
Elem.addeventlistener (type, handle, false);
else if (elem.attachevent)
Elem.attachevent ("On" + type, handle);
}
The function is placed in the list of elements of the event
Handlers[handler.guid] = handler;
});
Elem = null;
}
}

Gevent.hander is the function that the binding event actually performs
It's in the Gevent.hander. Special name Place but I don't know what to do with it.
Hander the event in the first package
packaging See gevent. Fix and SetEvent
The main thing is to do a copy of a native event and then put the incompatible method into a compatible way.
Then take the elements of events (event list)
And then iterate through this list of events to determine if the type is the key to the event list, and then execute the event
The return value is judged when the list function is executed
If you return False, you can also organize event bubbling and default behavior
Copy Code code as follows:

Win.gevent = {
Handle:function (event) {
var all, handlers;
Packaging event
event = Arguments[0] = Gevent.fix (Event | | window.event);

Event.currenttarget = this;

Here .....
var namespaces = Event.type.split (".");
Event.type = Namespaces.shift ();
all =!namespaces.length;
var namespace = RegExp (^|\\.) + Namespaces.slice (). Sort (). Join (". *\\.") + "(\\.| $)");
The list of events that take this element's behavior
Handlers = (data (this, "events") | | {}) [Event.type];
Traverse this list of events to perform the execution of something
for (Var j in handlers) {
var handler = Handlers[j];
if (all | | namespace.test (handler.type)) {
Pass in a reference to the handler function itself
So we can later remove it
The annotation on the JQ is written so that it is convenient to remove the event's handler by referencing it
But in the remove there is no use of the event handler do not know what is the use here and there are multiple events when this event was replaced
Event.handler = handler;
Execute an event and be an event that is invoked with an element can you? This execution element in the event RET is the return value of the function
var ret = handler.apply (this, arguments);
If there is a return value and the return value is false execution prevents event bubbling prevents the event default behavior from being performed
if (ret!== undefined) {
Event.result = ret;
if (ret = false) {
Event.preventdefault ();
Event.stoppropagation ();
}
}
}
}
},
Props: "Altkey attrchange attrname Bubbles button cancelable charcode clientX clientY ctrlkey currenttarget Data Detail EV Entphase fromelement Handler keycode metakey newvalue originaltarget pagex pagey prevvalue relatednode relatedTarget scree NX ScreenY shiftkey srcelement target toelement view Wheeldelta which ". Split (" "),
Fix:function (event) {
The new setevent will give the event a expando attribute if there is a description of the attribute that has already generated the event. Do not need to wrap the event on the second
if (Event[expando])
return event;
Keep one of the original event
New event This is different from the original event
var originalevent = event;
event = new SetEvent (originalevent);
Gets the attribute values for the original event's property value see This.props
for (var i = this.props.length, prop; i;) {
Prop = this.props[-I.];
event[prop] = originalevent[prop];
}
Make the target element the same as Event.target
if (!event.target)
Event.target = Event.srcelement | | Document Fixes #1925 where srcelement might is defined either
If a text node is found to fetch his parent node
if (Event.target.nodeType = 3)
Event.target = Event.target.parentNode;
if (!event.relatedtarget && event.fromelement)
Event.relatedtarget = Event.fromelement = = Event.target? Event.toElement:event.fromElement;
return event;
}
}
win.setevent = function (src) {
Allow instantiation without the ' new ' keyword
Event Object
if (src && src.type) {
This.originalevent = src;
This.type = Src.type;
Event type
}else
This.type = src;
TimeStamp is buggy to some events on Firefox (#3843)
So we won ' t rely on the native value
This.timestamp = Now ();
Mark it as fixed
This[expando] = true;
}
function Returnfalse () {
return false;
}
function Returntrue () {
return true;
}
Setevent.prototype = {
Preventdefault:function () {
var e = this.originalevent;
if (!e)
Return
If Preventdefault exists run it on the original event
if (E.preventdefault)
E.preventdefault ();
Otherwise set the ReturnValue property of the original event to False (IE)
E.returnvalue = false;
},
Stoppropagation:function () {
var e = this.originalevent;
if (!e)
Return
If stoppropagation exists run it on the original event
if (e.stoppropagation)
E.stoppropagation ();
Otherwise set the Cancelbubble property of the original event to True (IE)
E.cancelbubble = true;
},
Stopimmediatepropagation:function () {
this.isimmediatepropagationstopped = Returntrue;
This.stoppropagation ();
},
Isimmediatepropagationstopped:returnfalse
};

A complete example
Copy Code code as follows:

<! DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 transitional//en" "Http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
<meta http-equiv= "Content-type" content= "text/html; charset=gb2312 "/>
<title></title>
<body>
<div id= "VV" style= "height:200px;width:200px; Background-color: #f00; padding:20px; " >
<div id= "xx" style= "height:200px;width:200px; Background-color: #000000; " ></div>
</div>
<script type= "Text/javascript" >
(function (doc,undefined) {
function Now () {
return +new Date;
};
var win = this,
expando = "JQuery" + Now (),
UUID = 0,
cache = {};
Win.data = function (elem, name, data) {
var id = Elem[expando];
if (!id)
id = Elem[expando] = ++uuid;
if (Name&&!cache[id])
Cache[id] = {};
if (data!== undefined)
Cache[id][name] = data;
return name
? Cache[id][name]
: ID;
}
Win.removedata = function (elem, name) {
var id = Elem[expando];
if (name) {
if (Cache[id]) {
Delete Cache[id][name];
name = "";
for (name in cache[ID])
Break
if (!name)
Removedata (Elem);
}
}else{
try {
Delete Elem[expando];
catch (e) {
if (Elem.removeattribute)
Elem.removeattribute (expando);
}
Delete Cache[id];
}
}
Win.each = function (object, callback, args) {
var name, i = 0, length = object.length;
if (args) {
if (length = = undefined) {
For (name in object)
if (callback.apply (object[name], args) = = False)
Break
} else
for (; i < length;)
if (callback.apply (object[i++], args) = = False)
Break
} else {
if (length = = undefined) {
For (name in object)
if (Callback.call (object[name, name, object[name]) = = False)
Break
} else
for (var value = object[0];
I < length && Callback.call (value, I, value)!== false; Value = Object[++i]) {}
}
return object;
}
Win.gevent = {
Guid:1,
Add:function (Elem, types, handler) {
if (Elem.nodetype = 3 | | elem.nodetype = 8)
Return
if (elem.setinterval && elem!= window)
Elem = window;
An index that uniquely identifies a function makes it easier to delete the event later
if (!HANDLER.GUID)
Handler.guid = this.guid++;
Get the data under the events handle of the element
var events = data (Elem, "events") | | Data (Elem, "events", {}),
Handle =data (Elem, "handle") | | Data (Elem, "Handle", function () {
Gevent.handle is the function that is executed after various actions are triggered.
Gevent.handle.apply (Arguments.callee.elem, arguments);
});
Handle.elem = Elem;
Traverse event name because it can be click MouseOver
Each (Types.split (/\s+/), function (index, type) {
var namespaces = Type.split (".");
Get Event name
Type = Namespaces.shift ();
The thing behind the dot is a special name. You can specify the deletion when you delete him like CLICK.D
Record this particular name with the type of event
Handler.type = Namespaces.slice (). Sort (). Join (".");
To obtain whether the event already exists in this object.
var handlers = Events[type];
If the event does not exist for the element to bind the event
if (!handlers) {
Handlers = Events[type] = {};
if (Elem.addeventlistener)
Elem.addeventlistener (type, handle, false);
else if (elem.attachevent)
Elem.attachevent ("On" + type, handle);
}
The function is placed in the list of elements of the event
Handlers[handler.guid] = handler;
});
Elem = null;
},
Remove:function (Elem, types, handler) {
if (Elem.nodetype = 3 | | elem.nodetype = 8)
Return
Gets the list of all behaviors for this element, such as {click:{},mouseocer:{}}
var events = data (Elem, "events"), RET, index;
if (events) {
If there's no entry and exit behavior type, all events for this element are deleted
If the incoming is. xx This form of the inclusion of all the actions. XX named All Kill
if (types = = Undefined | | (typeof types = = "string" && types.charat (0) = = ".") ){
for (var type in events)
This.remove (Elem, type + types | | "") );
}else{
I don't know what to do.
if (Types.type) {
handler = Types.handler;
types = Types.type;
}
Because deleting events can support deletion of multiple deletions at a time such as Click MouseOver All to traverse delete
Each (Types.split (/\s+/), function (index, type) {
var namespaces = Type.split (".");
Type = Namespaces.shift ();
var namespace = RegExp (^|\\.) + Namespaces.slice (). Sort (). Join (". *\\.") + "(\\.| $)");
if (Events[type]) {
Delete this event if the 3rd parameter function is passed
if (handler)
Delete Events[type][handler.guid];
else{
Iterate through all the actions of this one
For (var handle in Events[type]) {
Handle the removal of namespaced events
To delete a function with a special name
If there is no special name regular then it is/^|..| $/can match empty so you can delete functions that don't have a special name
if (Namespace.test (Events[type][handle].type))
Delete Events[type][handle];
}
}
}
For (ret. Events[type]) break;
If Events[type] becomes empty, which is {} deletes the binding event for this element
if (!ret) {
if (Elem.removeeventlistener)
Elem.removeeventlistener (Type, data (Elem, "handle"), false);
else if (elem.detachevent)
Elem.detachevent ("On" + Type, data (Elem, "handle"));
ret = NULL;
Delete Events[type];
}
});
}
for (ret. events) break;
If the entire events of the element are found to be empty,
Empty out the handle and empty all his references.
if (!ret) {
var handle = data (Elem, "handle");
if (handle) Handle.elem = null;
Removedata (Elem, "events");
Removedata (Elem, "handle");
}
}
},
Handle:function (event) {
var all, handlers;
Packaging event
event = Arguments[0] = Gevent.fix (Event | | window.event);
Event.currenttarget = this;
Here .....
var namespaces = Event.type.split (".");
Event.type = Namespaces.shift ();
all =!namespaces.length;
var namespace = RegExp (^|\\.) + Namespaces.slice (). Sort (). Join (". *\\.") + "(\\.| $)");
The list of events that take this element's behavior
Handlers = (data (this, "events") | | {}) [Event.type];
Traverse this list of events to perform the execution of something
for (Var j in handlers) {
var handler = Handlers[j];
if (all | | namespace.test (handler.type)) {
Pass in a reference to the handler function itself
So we can later remove it
The annotation on the JQ is written so that it is convenient to remove the event's handler by referencing it
But in the remove there is no use of the event handler do not know what is the use here and there are multiple events when this event was replaced
Event.handler = handler;
Execute an event and be an event that is invoked with an element can you? This execution element in the event RET is the return value of the function
var ret = handler.apply (this, arguments);
If there is a return value and the return value is false execution prevents event bubbling prevents the event default behavior from being performed
if (ret!== undefined) {
Event.result = ret;
if (ret = false) {
Event.preventdefault ();
Event.stoppropagation ();
}
}
}
}
},
Props: "Altkey attrchange attrname Bubbles button cancelable charcode clientX clientY ctrlkey currenttarget Data Detail EV Entphase fromelement Handler keycode metakey newvalue originaltarget pagex pagey prevvalue relatednode relatedTarget scree NX ScreenY shiftkey srcelement target toelement view Wheeldelta which ". Split (" "),
Fix:function (event) {
The new setevent will give the event a expando attribute if there is a description of the attribute that has already generated the event. Do not need to wrap the event on the second
if (Event[expando])
return event;
Keep one of the original event
New event This is different from the original event
var originalevent = event;
event = new SetEvent (originalevent);
Gets the attribute values for the original event's property value see This.props
for (var i = this.props.length, prop; i;) {
Prop = this.props[-I.];
event[prop] = originalevent[prop];
}
Make the target element the same as Event.target
if (!event.target)
Event.target = Event.srcelement | | Document Fixes #1925 where srcelement might is defined either
If a text node is found to fetch his parent node
if (Event.target.nodeType = 3)
Event.target = Event.target.parentNode;
if (!event.relatedtarget && event.fromelement)
Event.relatedtarget = Event.fromelement = = Event.target? Event.toElement:event.fromElement;
return event;
}
}
win.setevent = function (src) {
Allow instantiation without the ' new ' keyword
Event Object
if (src && src.type) {
This.originalevent = src;
This.type = Src.type;
Event type
}else
This.type = src;
TimeStamp is buggy to some events on Firefox (#3843)
So we won ' t rely on the native value
This.timestamp = Now ();
Mark it as fixed
This[expando] = true;
}
function Returnfalse () {
return false;
}
function Returntrue () {
return true;
}
Setevent.prototype = {
Preventdefault:function () {
var e = this.originalevent;
if (!e)
Return
If Preventdefault exists run it on the original event
if (E.preventdefault)
E.preventdefault ();
Otherwise set the ReturnValue property of the original event to False (IE)
E.returnvalue = false;
},
Stoppropagation:function () {
var e = this.originalevent;
if (!e)
Return
If stoppropagation exists run it on the original event
if (e.stoppropagation)
E.stoppropagation ();
Otherwise set the Cancelbubble property of the original event to True (IE)
E.cancelbubble = true;
},
Stopimmediatepropagation:function () {
this.isimmediatepropagationstopped = Returntrue;
This.stoppropagation ();
},
Isimmediatepropagationstopped:returnfalse
};
}) (document);
var $ = function (ID) {return document.getElementById (ID)}
var a = function () {alert (1)}
Window.onload = function () {
Gevent.add ($ (' xx '), ' click ', a);
Gevent.add ($ (' xx '), ' click ', function () {alert (1)});
Gevent.add ($ (' xx '), ' click ', function () {alert (2)});
Gevent.add ($ (' xx '), ' click ', function () {alert (3)});
Gevent.add ($ (' xx '), ' click.xx ', function () {alert (4)});
}
</script>
</body>

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.