Welcome. My column Check out a series of articles.
Previously, I only knew that click events would only start when clicking on elements in browsers, as would other events, requiring human mouse operations.
Later, with the continuous deepening of learning, it was known that the original JS can write functions to control the execution of events, so that it is interesting to write code. I remember a long time ago, some malicious websites, clearly the mouse did not click, but was forced to click on a link by the website, probably in this way.
Native event
In fact, the native events of JS have been well done, but jQuery encapsulates them and makes them better.
about document.createEvent Here is a simple example of event clicks:
var fn = function(){ console.log('click'); } var button = document.getElementById('#id'); button.addEventListener('click', fn); // Click on Event MouseEvent var myClick = document.createEvent('MouseEvent'); myClick.initMouseEvent('click', false, false, null); // implement button.dispatchEvent(myClick); // 'click'
In addition to mouse events, you can customize events:
// Customize an event test.click button.addEventListener('test.click', fn); var testEvent = document.createEvent('CustomEvent'); // CusmEvent can also be initialized as a mouse event, not necessarily a custom event testEvent.initCustomEvent('test.click', false, false, null); button.dispatchEvent(testEvent); // 'click'
JS native simulation events are still very convenient to use, and the above is native.
But jQuery also has its own custom event scenario.
jQuery.trigger
jQuery.trigger can be compared with HTMLElement.dispatchEvent events, which are used to simulate and execute listened events.
How to use
For use, it's simpler. .trigger():
var $body = $(document.body); // First Bind Events $body.on('click', function(){ console.log('click'); }) // implement $body.trigger('click'); //'click'
trigger also supports more parameters and can also customize events:
$body.on('click.test', function(e, data1, data2){ console.log(data1 + '-' + data2); }) $body.trigger('click.test', ['hello', 'world']);
trigger source code
The source code of trigger is somewhat simple, because it is still handled by jQuery.event:
jQuery.fn.extend( { trigger: function(type, data){ return this.each(function(){ jQuery.event.trigger(type, data, this); }) }, // triggerHandler handles the first event without triggering the default event triggerHandler: function( type, data ) { var elem = this[ 0 ]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } } );
So the trigger event is back to jQuery.event.
jQuery.event.trigger
Actually, trigger and add + handler functions are very similar. They are basically searching for caches from data cache and executing callback functions. You need to consider whether you want to execute the default event, where the fourth parameter is true.
jQuery.extend(jQuery.event, { // ONLEY Handlers denotes that bubble events are not considered trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; cur = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // Asynchronous non-conflict if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf( "." ) > -1 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split( "." ); type = namespaces.shift(); namespaces.sort(); } ontype = type.indexOf( ":" ) < 0 && "on" + type; // Refitting native event events event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // Determine whether only the current trigger event is executed without bubbling event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join( "." ); event.rnamespace = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Bubble the document and store the bubbles in the eventPath array if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === ( elem.ownerDocument || document ) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Execution on demand i = 0; while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // Getting callback functions from data cache handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { // implement handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && handle.apply && acceptData( cur ) ) { event.result = handle.apply( cur, data ); if ( event.result === false ) { event.preventDefault(); } } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( ( !special._default || special._default.apply( eventPath.pop(), data ) === false ) && acceptData( elem ) ) { // Call a native DOM method on the target with the same name as the event. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, })
summary
In jQuery.event.trigger, it is interesting to simulate bubbling mechanism. The general idea is:
Save the current elem into an array;
Find the parent element of the current elem, if it matches, push into the array, repeat the first step, otherwise the next step;
Traverse the array to see if the type event is bound from the data cache, and then execute it in turn.
Bubble event is the process of bubbling from inside to outside, which is not very complicated.
event events should be all about that.
Reference resources
Decrypting jQuery Event Core - Custom Design (3)
MDN createEvent
Decrypting jQuery Event Core - Simulated Events (4)
On github Source address Welcome to star.
Welcome. My blog Communication.