There is a data method in jq, which binds relevant data to DOM elements. When an event is bound to the dom using the jq method, the corresponding time list will be generated
You can see the example below (please view it in firefox because objects in firefox support toSource())
data is used to bind data to elements
The data source is the cache object
When the element is bound to data, an attribute jQueryxxx xxx will be added to the element. For the timestamp of jq execution
It should be explained here that there is a uuid which is accumulated
The value of jQueryxxx is this uuid
The key of cache is this uuid
The value is the data to be stored
data is very important for event binding........................
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 add the event
jq which is in jQuery.event The add method
implements some functions in the add method
takes the events of the element and handles the data bound by these two data
events stores the event list
The format is as follows
{
click: [{handler:function(){},type:"click",guid:'xx'}.....],
mouse:[......]
}
Handle is the executed function
(all execution functions are the same. They traverse the event list to execute the corresponding event)
Then traverse the types because multiple events can be bound
The callback function also There will be several attributes
assuming the callback function is handler
handler.guid = gevent.guid
handler.type = name
name should be considered a special name for easy deletion
such as
$('#xx')
.bind('click',function(){})
.bind('click.d',handler)
name is d
Delete You can only delete the d event without deleting the click event above
Finally, bind the event to the element, but the functions executed are all
function(){
gevent.handle.apply(arguments.callee .elem, arguments);
});
win.gevent = {
guid : 1,
add : function (elem, types, handler){
if ( elem.nodeType == 3 || elem.nodeType == 8)
return;
if ( elem.setInterval && elem != window )
elem = window;
//Give the function a unique index to facilitate deleting 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 when various behaviors are triggered The function that will be executed
gevent.handle.apply(arguments.callee.elem, arguments);
});
handle.elem = elem;
//Traverse the event name because it can be click mouseover
each(types.split(/s /), function(index, type) {
var namespaces = type.split(".");
//Get the event name
type = namespaces .shift();
//Removing the thing after the dot is a special name. When deleting, you can specify to delete it, such as click.d
//Use the event type to record this special name
handler .type = namespaces.slice().sort().join(".");
//Get whether the event already exists in the events object
var handlers = events[type];
//If the event does not exist, bind the event to the element
if (!handlers) {
handlers = events[type] = {};
if (elem.addEventListener)
elem.addEventListener (type, handle, false);
else if (elem.attachEvent)
elem.attachEvent("on" type, handle);
}
//Place the function in the event of the element In the list
handlers[handler.guid] = handler;
});
elem = null;
}
}
gevent.hander is bound The function
that determines the actual execution of the event is also available in gevent.hander. The place is specially named but I don’t know what it is used for.
In the handler, the event is packaged first
For packaging, see gevent.fix and setEvent
Mainly make a copy of a native event and then synthesize the incompatible methods into compatible writing
Then take the events (event list) of the element
Then traverse the event list to determine whether the type is the key of the event list If yes, execute the event
The return value will be judged when executing the list function
If false is returned, event bubbling and default behavior can also be organized
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(".*\.") "(\.|$)");
//Get the event list of this behavior of this element
handlers = (data(this, "events" ) || {} )[event.type];
//Traverse this event list to execute the execution thing
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 that we can later remove it
// on jq The comment is written like this. The event handler refers to this event for convenience and can be removed later
// However, the event handler is not used in remove. I don’t know what the use is here. And when there are multiple events, this event is Replace
event.handler = handler;
//Execute the event and it is an event called with an element. You can use this in the event to execute the element ret as the return value of the function
var ret = handler.apply(this, arguments);
//If there is a return value and the return value is false, the execution prevents the event from bubbling and prevents the execution of the event. Default behavior
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 eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix : function(event){
//new setEvent will give an expando attribute to the event. If there is an attribute, it means that the event has been generated. There is no need to wrap the event again
if (event[expando] )
return event;
//Keep an original event
// new a new event This is different from the original event
var originalEvent = event;
event = new setEvent (originalEvent);
//To get the attribute values of the original event, see this.props
for ( var i = this.props.length, prop; i; ){
prop = this. props[ --i ];
event[ prop ] = originalEvent[ prop ];
}
//Unify the target element into event.target
if ( !event.target )
event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
//If it is found to be a text node, take its 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 for 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