Overview
The event implementation in dojo is not complicated, of course I Just from the point of view of code volume, but the gold content is still very high, and it is easy to implement custom event monitoring, and it also supports publish and subscribe mode. Let’s take a look at the source code level.
How the event mechanism in dojo is implemented Yes, after in-depth understanding, you can even copy it and use it directly in others.
The use of the event mechanism mainly involves the following 4 functions:
1. dojo.connect(); Establish event monitoring connection
2. dojo.disconnect(); Disconnect event monitoring connection
3. dojo.publish(); Publish topic
4. dojo.subscribe(); Subscribe to topic
5. dojo.unsubscribe(); Unsubscribe topic
In this article, first talk about connect mechanism, and publish and subscribe implementation The connect mechanism is also used in, which will be explained in the next article.
示例
讲解之前先看一个示例:
function Foo() {this.name = "Foo"; this.output = function() {var result = "output function in "+ this.name; console.info(result); return result; };}function Bar () {this.name = "Bar"; this.output = function() {var result = "output function in "+ this.name; console.info(result); return result; }}var foo = new Foo( ); var bar = new Bar();//Non-dom node event monitoring var handle = dojo.connect(foo, "output", bar, "output");foo.output(); //will trigger bar.output Call dojo.disconnect(handle); //disconnect//add event listener for dom node handle = dojo.connect(dojo.byId("someId"), "click", function(){ // do something}) ;//Remove event listener dojo.disconnect(handle);
dojo._listener object
Before explaining the connect mechanism, you must first understand the dojo._listener object, which is the key implementation of the general mechanism for handling non-dom node events, as follows:
dojo._listener = {// Create a dispatcher function, the return value of the function is also a function getDispatcher: function(){ return function(){ // c is the current This anonymous function, its _listeners and target attributes will be set in the add function, which respectively represent the listener list and target function of the target function // The target function is the function to be listened to, and the listener list is triggered when the listened function is called The function call var ap = Array.prototype, c = arguments.callee, ls = c._listeners, t = c.target, // Use the return value of the original target function as the return value of the anonymous function r = t && t.apply( this, arguments), //call the target function // make local copy of listener array so it is immutable during processing // make a copy of the listener list, the purpose of which is to ensure that the elements in the list are not Will change // because it is possible that the list of listeners is being traversed and called to it, but listeners are being removed elsewhere i, lls = [].concat(ls); // invoke listeners after target function // After the original target function is called, call each listener in turn for(i in lls){ if(!(i in ap)){ // Note that this, this points to the object that called the original target function, and The listener function and anonymous function parameters are the same lls[i].apply(this, arguments);}} // return the return value of the original target function return r; }; }, // add a listener to the source object by The parameter name shows that source is the source object, method is the function name, and listener is the listener (callback function) add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ // if If source does not exist, assign wi ndow source = source || dojo.global; // The source method is either null, a dispatcher, or some other function var f = source[method]; // Ensure a dispatcher // The f function cannot be null, and the When the event listener is registered for the first time, f._listeners does not exist if(!f || !f._listeners){ // Get a dispatcher function, which is the anonymous function returned by getDispatcher, at this time the anonymity is not called var d = dojo._listener.getDispatcher(); // original target function is special // assign the target attribute to the original target function d.target = f; // initialize an empty listener list d._listeners = []; // Redefine the original target function to the dispatcher function, so when the original target function is called, the dispatcher function is actually called, // which is the anonymous function returned by getDispatcher, only this can trigger the call process of the listener function f = source[method] = d;} // Add the listener to the list and return the position of the listener in the listener list (index+1) return f._listeners.push(listener); /*Handle*/ }, // Remove a listener from the source object. From the parameter name, source is the source object, method is the function name, and handle is the listener handle. remove: function(/*Object*/ source, /*String*/ method, / *Handle*/ handle){ // Get the dispatcher function var f = (source || dojo.global)[method]; // Because the handle value is index+1, the handle value is greater than 0 to be valid, and the listener index The value is handle-1 if(f && f._listeners && handle--){ // Remove the listener from the list of listeners delete f._listeners[handle];} }};
del object
del object is the realization of the dom node event mechanism, this is very simple , Call addEventListener and removeEventListener respectively.
var del = (dojo._event_listener = {add: function(/*DOMNode*/ node, /*String*/ name, /*Function*/ fp){ // Omit some code... // Add event listener for dom node node.addEventListener(name, fp, false); return fp; /*Handle* / }, remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){ if(node){ event = del._normalizeEventName(event); if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){ event = (event == "mouseenter")? "mouseover": "mouseout";} // Remove event listener from dom noe node. removeEventListener(event, handle, false);}} // Some functions used in the add and remove functions are omitted to deal with browser compatibility issues. Ignoring them does not prevent understanding of the event mechanism});
dojo.connect
After cleaving the above content, look at the connect and disconnect functions. Simple:
dojo.connect = function(/*Obj ect|null*/ obj, /*String*/ event, /*Object|null*/ context, /*String|Function*/ method, /*Boolean?*/ dontFix){ var a=arguments, args=[] , i=0; // if a[0] is a String, obj was omitted //If the first parameter is of type String, the obj parameter is ignored args.push(dojo.isString(a[0])? null: a[i++], a[i++]); // if the arg-after-next is a String or Function, context was NOT omitted var a1 = a[i+1]; // if the third parameter is String or Function type, ignore the context parameters // The purpose of processing these parameters is to facilitate the transfer of parameters, a bit of a feeling of function overloading args.push(dojo.isString(a1)||dojo.isFunction(a1)? A[i++]: null, a[i++]); for(var l=a.length; i
dojo.disconnect
dojo.disconnect = function(/*Handle*/ handle){ // The handle parameter is the return value of the connect function, which is an array if(handle && handle[0] !== undefined){ //Call the _disconnect function dojo._disconnect.apply(this, handle); // After disconnecting, delete the object reference delete handle[0]; }}; dojo._disconnect = function(obj, event, handle, listener){ // The four parameters of this function correspond to the four elements in the return value array of the connect function. // Call the remove method of the corresponding event mechanism object to remove the listener ([dojo ._listener, del, node_listener][listener]).remove(obj, event, handle);};PS:dojo version is dojo-release-1.6.3