Home >Web Front-end >JS Tutorial >A brief discussion on the principle of jQuery event binding_jquery

A brief discussion on the principle of jQuery event binding_jquery

WBOY
WBOYOriginal
2016-05-16 16:22:35992browse

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, a corresponding time list will be generated
You can see the following example (please view it in firefox because objects in firefox support toSource())

Copy code The code is as follows:














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 will be added to the element. xxx is the timestamp of executing jq
Let me explain here, there is a uuid which is cumulative
The value of jQueryxxx is this uuid
The cache key is this uuid
value is the data to be saved
Data is very important for event binding........................

Copy code The code is 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 adding events

In jq is the add method in jQuery.event
Some functions are implemented in the add method
Get the events of the element and handle the data bound to these two data
events stores a list of events
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 and execute the corresponding event)
Then traverse the types because multiple events can be bound
The callback function will also give several attributes
Assume the callback function is handler
handler.guid = gevent.guid
handler.type = name
name should be considered a special name for easy deletion
For example
$('#xx')
.bind('click',function(){})
.bind('click.d',handler)
The name is d
When deleting, you can only delete the d event without deleting the click event above

Finally, the event is bound to the element, but the functions executed are all
function(){
gevent.handle.apply(arguments.callee.elem, arguments);
});

Copy code The code is 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;
//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 the function that will be executed after various behaviors 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();
//Remove the thing after the point. It 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);             }
//Put the function into the event list of the element
                 handlers[handler.guid] = handler;         });
elem = null; }
}


gevent.hander is the function actually executed by the bound event
There is also a place for special naming in gevent.hander, but I don’t know what it is used for
The event is first packaged in the handler
For packaging see gevent.fix and setEvent
The main thing is to make a copy of a native event and then combine the incompatible methods into compatible writing
Then get the events (event list) of the element
Then traverse the event list to determine whether type is the key of the event list. If so, execute the event
The return value will be judged when executing the list function
If you return false, you can also organize event bubbling and default behavior

Copy code The code is 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(".*\.") "(\.|$)");
//Get the event list of the behavior of this element
            handlers = (data(this, "events") || {} )[event.type]; //Traverse this event list and execute the things to be executed
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
                             // The comment on jq is written like this. Reference the event handler to this event for convenience and remove it later
                                                // But in the remove, the event handler is not used. I don’t know what the use is here. And when there are multiple events, this event is replaced
                  event.handler = handler;
//Execute the event and it is an event called with an element. You can execute this element in the event and 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, the execution prevents the event from bubbling and the default behavior of the execution event is blocked 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 the event an expando attribute. If there are any of the attributes, it means that the event has been generated and 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);
//Get the attribute value of the original event. For what attribute values ​​there are, see this.props
for ( var i = this.props.length, prop; i; ){
              prop = this.props[ --i ];
            event[ prop ] = originalEvent[ prop ];
}
//Unify the target elements 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, get 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

Copy code The code is as follows:

http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
http://www.w3.org/1999/xhtml">










以上内容只是自己的一些理解,水平有限,难免有错,望指正...

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn