DOJO event driver programming event binding

What is event driven?

   Event-driven programming is a programming model driven by events. The module passively waits for notifications (notification), and its behavior depends on external surprises. Sending events is event-driven and conforms to the event-driven programming (Event-Driven Programming, EDP for short) model.

  What is an event? In layman’s terms, it is something concerning that has happened. In software, it is generally expressed as a change in the state of some information of a program. Event-driven systems generally provide two types of built-in events: one type is low-level events or native events. In GUI systems, this Class events are directly triggered by hardware devices such as the mouse and keyboard; one is semantic events, which generally represent the user’s behavior logic and are a combination of several low-level events. For example, drag-and-drop usually means moving the object being dragged and dropped, and it consists of three low-level events: mouse down, mouse movement, and mouse release.

   There is also a type of user-defined event. They can be packaging based on the original built-in events, or they can be pure virtual events. In addition, the programmer can not only define events, but also generate events. Although most events are natural events triggered by the outside world, sometimes programmers need to actively trigger some events, such as simulating user mouse clicks or keyboard input. Such events are called synthetic events. These have further enriched and improved the event system and event mechanism, making event-driven programming more permeable.

  

   The picture above is a typical event-driven model. The event handler is registered in advance on the concerned event source, and the latter publishes it irregularly event object, after the event manager conversion (translate), merge (coalesce), After queuing (enqueue), dispatch (dispatch) and other centralized processing, the event processor receives the event and processes it accordingly. Through the event mechanism, a loosely coupled many-to-many relationship is established between event sources and event processors: one event source can have multiple processors, and one processor can monitor multiple event sources. From another perspective, treating the event processor as the server and the event source as the client is a client-server model. The session between each server and its client is asynchronous, that is, after processing a client’s request, there is no need to wait for the next request. Switch to service to other customers.

   In the web environment, the event source is acted by the DOM. The event manager is transparent to web developers and managed by the browser. The event handler is the callback we bind to the dom event. function.

  Web event processing flow

  The DOM2.0 model divides the event processing process into three stages: one, the event capture stage, the second, the event target stage, and the third, the event bubbling stage. As shown:

  

  

   Event capture: When an element triggers an event (such as onclick), the top-level object document will emit an event stream, following the DOM The nodes of the tree flow to the target element node until it reaches the target element where the event actually occurred. In this process, the listener function corresponding to the event will not be triggered.

   Event target: After reaching the target element, execute the corresponding processing function of the event of the target element. If the listener function is not bound, it will not be executed.

   event bubbling: start from the target element and spread to the top element. If there is a node bound to the corresponding event processing function on the way, these functions will be triggered at once. If you want to prevent the event from bubbling, you can use e.stopPropagation() (Firefox) or e.cancelBubble=true (IE) to organize the bubbling propagation of the event.

   However, in this end-of-the-day era, the handling of events by the two major factions of browsers often troubles front-end programmers. Therefore, any front-end library must first unify the event mechanism.

  Event binding in dojo

What problems can the   dojo event system help us solve?

  1. Solve browser compatibility issues: trigger sequence, this keyword, standardized event objects (attributes, methods)
  2. Can be added to an event type Multiple event processing functions, you can add event processing functions of multiple event types at once
  3. Unified event encapsulation, binding, execution, and destruction mechanisms
  4. Support custom events
  5. li>

  6. Extended combination events

   The code for handling browser events in dojo is located in the dojo/on module, and the signature of this function can be viewed on the official website:

p>

  

   where type can be an event name such as: “click”

< img src="/wp-content/uploadshttp:/img.voidcn.com/vcimg/static/loading.png" alt="copy code" d="5338" s="48f_eef" t="gif">
require(["dojo/on", "dojo/_base/window"], function(on, win){
var signal = on(win.doc, "click", function(){
// remove listener after first event
signal.remove();
// do something else...
});
});
copy code

   can also be a comma A string composed of multiple event names separated, such as: “dblclick,click”

require("dojo/on", function(on){
on(element,
"dblclick, touchend", function(e){
// handle either event
});
});

   can also be separated by a colon “selector:eventTy The string used for event delegation in pe” format, such as: “.myClass:click”

require(["dojo/on", "dojo/_base/window" , "dojo/query"], function(on, win){
on(win.doc ,
".myClass:click", clickHandler);
});

   is also possible Is a function, such as: touch.press, on.selector()

require(["dojo/on", "dojo/mouse", "dojo/query! css2"], function(on, mouse){
on(node, on.selector(< /span>".myClass", mouse.enter), myClassHoverHandler);
});

  < /p>

   Check the source code of the on function

copy code
 var on = function(target, type, listener, dontFix){

if(typeof target.on == "function" && typeof type != "function" && !target.nodeType){
// delegate to the target's on() method, so it can handle it's own listening if it wants (unless it
// is DOM node and we may be dealing with jQuery or Prototype's incompatible addition to the
// Element prototype
return target.on(type, listener);
}
// delegate to main listener code
return on .parse(target, type, listener, addListener, dontFix, this);
};
Copy code

   If the target has its own on method, call the target itself The on method, such as the _WidgetBase class has its own on method, and the jquery object also has its own on method, where the this keyword points to window.

  

   Let’s take a look at the process of event resolution:
  1. If type is a method, it will be handled by type itself; for example, touch.press , On.selector
  2. Multi-event processing; events may be strings separated by comma keys, so turn them into a string array
  3. Call on.parse for the event array in turn
  4. Add event listener
copy code
on.parse = function(target, type, listener, addListener, dontFix, matchesTarget){
if(type.call){
// event handler function
//< /span> on(node, touch.press, touchListener);
return span> type.call(matchesTarget, target, listener);
}

if(type instanceof Array){
// allow an array of event names (or event handler functions)
events = type;
}
else if(type.indexOf(",")> -1){
// we allow comma delimited event names, so you can register for multiple events at once
var events = type.split(/\s*,\s*/);
}
if(events){
var handles = [];
var i = 0;
var eventName;
while (eventName = events[i++]){
handles.push(on.parse(target, eventName, listener, addListener, dontFix, matchesTarget));
}
handles.remove
= function(){
for(var i = 0; i ){
handles[i].remove();
}
};
return handles;
}
return addListener(target, type, listener, dontFix, matchesTarget);
};
copy code

  

   Then take a look at the processing process of the event listener:
  1. Handle event delegation, dojo event delegation The writing format is: “selector: eventType”, which will be directly handed over to on.selector for processing
  2. For the handling of touchevent events, we will talk about the specific analysis later
  3. The correction of stopImmediatePropagation
  4. >

  5. For browsers that support addEventListener, use the browser’s own interface for processing
  6. For browsers that do not support addEventListener, enter the fixAttach function
View Code

   From the above analysis, we can draw several conclusions:

  • For no special EventType and common events, addEventListener is used to add Incident.
  • The special EventType uses another method to add events (fixAttach).
  • The event delegation is handled by on.selector

  

  Let’s take a look at fixAttach in detail:
  1. Correct the event listener. The process returns a closure. The event object is corrected in the closure. The following aspects:
  • target
  • currentTarget
  • relatedTarget
  • stopPropagation
  • preventDefault
  • The coordinate position of the event is compatible with the normalizeEvent of dom-geometry for processing
  • Keycode and charcode processing

Call the event listener passed in on , If stopImmediatePropagation is used in the listener to cache lastEvent for later use

  2. For low version browsers, prevent frames and add events for elements linked to the DOM tree For memory leaks caused by customizing an Event object, add all event listeners as attributes to the Event object.
  3. Use aspect.after to construct a function chain to store the event listener when not in the 2 conditions, which ensures that the call sequence of the listener is consistent with the addition sequence.

  

View Code

  About aspect For the specific working principle of .after, please see my article: Javascript event mechanism compatibility solution

  

   Next, let’s take a look at the handling of delegates:

< p>  < /p>

   binds the click event to the document. After the click event starts, it is judged whether the event.target satisfies the selector “button.myclass”, and if it is satisfied, the clickHandler is executed. Why do we need to judge whether event.target meets the selection conditions? There may be a or span under the document. We only need to delegate the click of a to the document, so we must determine whether the selection conditions are met. There are two main functions to solve the delegation process: on.selector, on.matches.

  

  on.selector returns an anonymous function, and there are several things in the anonymous function. Matters:
  1. Processing matchesTarget is used in the matches method
  2. If eventType contains bubble method for special processing
  3. Other common situations, binding for proxy elements Event callback

  

   The red box is to determine whether event.target matches the selector. If it matches, the event callback clickHandler is triggered.

p>

  

  on.matches did the following things:
  1. Get a valid matchesTarget, matchesTarget is an object with a matches method, the default is dojo .query
  2. Process the textNode
  3. Check whether the ancestor elements of event.target meet the matching conditions
View Code

   Compare the event handling process of dojo and jquery, you can Found that jQuery is even better in event storage:

  dojo is directly bound to the dom element,jQuery does not bind the event handler directly to the DOM element, but through .data Stored in the cache.cahce.

   When declaring binding:

  • First assign a unique ID to the DOM element, and the bound event is stored in
    .cahce[Unique ID ][.expand ][‘events’ ], and events is a key-value mapping object, the key is the event type, and the corresponding value is an array of event processing functions, and finally bound to the DOM element (addEventListener/attachEvent) An event handling function eventHandle, this process is implemented by jQuery.event.add.

  When binding is executed:

  • When the event is triggered, eventHandle is executed, and eventHandle goes to $.cache to find the binding. The event handler function is executed. This process is implemented by jQuery.event. trigger and jQuery.event.handle.
  • The event destruction is implemented by jQuery.event.remove. Remove destroys the event array stored in the cache $.cahce. When all the events in the cache are destroyed, call removeEventListener/ detachEvent to destroy it. The event handling function eventHandle on DOM elements.

  

   The above is the main content of the dojo event module. If you look at the Javascript event mechanism compatibility solution, it will be more helpful to understand the dojo/on module.

  1. Solve browser compatibility issues: trigger sequence, this keyword, normalized event objects (attributes, methods)
  2. Add multiple event processing functions to the event type, and you can add event processing functions of multiple event types at one time
  3. Unified event encapsulation, binding, execution, and destruction mechanisms
  4. Define events
  5. Extended combination events

copy code
require(["dojo/on", "dojo/_base/window"], function(on , win){
var signal = on(win.doc, "click", function(){
// remove listener after first event
signal.remove();
// do something else...
});
});
copy code

copy code

Copy code

require("dojo/on", function(on){
on(element,
"dblclick, touchend", function(e){
// handle either event
});
});

require(["dojo/on", "dojo/_base/windo w", "dojo/query"], function(on, win){
on(win .doc,
".myClass:click", clickHandler);
});

require(["dojo/on", "dojo/mouse", "dojo/query!css2"], function(on, mouse){
on(node, on.selector(
".myClass", mouse.enter), myClassHoverHandler);
});

copy code
var on = function(target, type, listener, dontFix){

if(typeof target. on == "function" && typeof type != "function" && !target.nodeType){
// delegate to the target's on() method, so it can handle it's own listening if it wants (unless it
// is DOM node and we may be dealing with jQuery or Prototype's incompatible addition to the< br /> // Element prototype
return target.on(type, listener);
}
// delegate to main listener code
return on.parse (target, type, listener, addListener, dontFix, this);
};
copy code

copy code

copy code

   If the target has its own on method, call the target Own on method, such as the _WidgetBase class has its own on method, and for example, the jquery object will also have its own on method, where the this keyword points to window.

   Let’s take a look at the process of event resolution:

Copy code < /div>

on.parse = function(target, type, listener, addListener, dontFix, matchesTarget) {
if(type.call){
// event handler function
// on(node, touch.press, touchListener);
return span> type.call(matchesTarget, target, listener);
}

if(type instanceof Array){
// allow an array of event names (or event handler functions)
events = type;
}
else if(type.indexOf(",")> -1){< br /> // we allow comma delimited event names, so you can register for multiple events at once
var events = type.split(/\s*,\s*/);
}
if(events){
var handles = [];
var i = 0;
var eventName;
while(eventName = events[i++]){
handles.push(on.parse(target, eventName, listener, addListener, dontFix, matchesTarget));
}
handles.remove
= function(){
for(var i = 0; i ){
handles[i].remove();
}
};
return handles;
}
return addListener(target, type, listener, dontFix, matchesTarget );
};
copy code

copy code

Copy code

   Then look at the processing process of the event listener:

< img id="code_img_closed_b7aafd3e-d072-4750-a000-8cfa01df10b7" class="code_img_closed" src="/wp-content/uploadshttp:/img.voidcn.com/vcimg/static/loading.png" alt="" d= "11588" s="483_5f2" t="gif"> View Code

  Let’s take a look at fixAttach in detail:

  1. Correct the event listener. The process returns a closure. The event object is corrected in the closure. The following aspects:

  • target
  • currentTarget
  • relatedTarget
  • stopPropagation
  • preventDefault
  • The coordinate position of the event is compatible with the normalizeEvent of dom-geometry for processing< /li>
  • Keycode and charcode processing

Call the event listener passed in in on, if stopImmediatePropagation is used in the listener, the lastEvent will be cached for future use

  2. For low-version browsers to prevent memory leaks caused by adding events to the frames and elements linked to the DOM tree, here we customize an Event object and add all event listeners as attributes. On this Event object.

  3. Use aspect.after to construct a function chain to store event listeners when not in the 2 conditions, which ensures that the call order of the listeners is consistent with the addition order.

View Code

  on.selector returns an anonymous Function, the anonymous function did several things:

  on.matches did the following things:

View Code

.cahce[Unique ID][.expand ][‘events’ ], and events is a key-value mapping object, the key is Event type, the corresponding value is an array composed of event handling functions, and finally an event handling function eventHandle is bound (addEventListener/attachEvent) on the DOM element. This process is implemented by jQuery.event.add.

Leave a Comment

Your email address will not be published.