您的位置: 首页 - 互联网

JavaScript

var mediator = (function(){
// Storage for topics that can be broadcast or listened to
    var topics = {};
// Subscribe to a topic, supply a callback to be executed
    // when that topic is broadcast to
    var subscribe = function( topic, fn ){
if ( !topics[topic] ){
          topics[topic] = [];
        }
topics[topic].push( { context: this, callback: fn } );
return this;
    };
// Publish/broadcast an event to the rest of the application
    var publish = function( topic ){
var args;
if ( !topics[topic] ){
          return false;
        }
args = Array.prototype.slice.call( arguments, 1 );
        for ( var i = 0, l = topics[topic].length; i < l; i++ ) {
var subscription = topics[topic][i];
            subscription.callback.apply( subscription.context, args );
        }
        return this;
    };
return {
        publish: publish,
        subscribe: subscribe,
        installTo: function( obj ){
            obj.subscribe = subscribe;
            obj.publish = publish;
        }
    };
}());
// Pass in a context to attach our Mediator to.
// By default this will be the window object
(function( root ){
function guidGenerator() { /*..*/}
// Our Subscriber constructor
  function Subscriber( fn, options, context ){
if ( !(this instanceof Subscriber) ) {
return new Subscriber( fn, context, options );
}else{
// guidGenerator() is a function that generates
      // GUIDs for instances of our Mediators Subscribers so
      // we can easily reference them later on. We're going
      // to skip its implementation for brevity
this.id = guidGenerator();
      this.fn = fn;
      this.options = options;
      this.context = context;
      this.topic = null;
}
  }
})();
// Let's model the Topic.
// JavaScript lets us use a Function object as a
// conjunction of a prototype for use with the new
// object and a constructor function to be invoked.
function Topic( namespace ){
if ( !(this instanceof Topic) ) {
    return new Topic( namespace );
  }else{
this.namespace = namespace || "";
    this._callbacks = [];
    this._topics = [];
    this.stopped = false;
}
}
// Define the prototype for our topic, including ways to
// add new subscribers or retrieve existing ones.
Topic.prototype = {
// Add a new subscriber
  AddSubscriber: function( fn, options, context ){
var callback = new Subscriber( fn, options, context );
this._callbacks.push( callback );
callback.topic = this;
return callback;
  },
...
StopPropagation: function(){
  this.stopped = true;
},
GetSubscriber: function( identifier ){
for(var x = 0, y = this._callbacks.length; x < y; x++ ){
    if( this._callbacks[x].id == identifier || this._callbacks[x].fn == identifier ){
      return this._callbacks[x];
    }
  }
for( var z in this._topics ){
    if( this._topics.hasOwnProperty( z ) ){
      var sub = this._topics[z].GetSubscriber( identifier );
      if( sub !== undefined ){
        return sub;
      }
    }
  }
},
AddTopic: function( topic ){
  this._topics[topic] = new Topic( (this.namespace ? this.namespace + ":" : "") + topic );
},
HasTopic: function( topic ){
  return this._topics.hasOwnProperty( topic );
},
ReturnTopic: function( topic ){
  return this._topics[topic];
},
RemoveSubscriber: function( identifier ){
if( !identifier ){
    this._callbacks = [];
for( var z in this._topics ){
      if( this._topics.hasOwnProperty(z) ){
        this._topics[z].RemoveSubscriber( identifier );
      }
    }
  }
for( var y = 0, x = this._callbacks.length; y < x; y++ ) {
    if( this._callbacks[y].fn == identifier || this._callbacks[y].id == identifier ){
      this._callbacks[y].topic = null;
      this._callbacks.splice( y,1 );
      x--; y--;
    }
  }
},
Publish: function( data ){
for( var y = 0, x = this._callbacks.length; y < x; y++ ) {
var callback = this._callbacks[y], l;
          callback.fn.apply( callback.context, data );
l = this._callbacks.length;
if( l < x ){
        y--;
        x = l;
      }
    }
for( var x in this._topics ){
      if( !this.stopped ){
        if( this._topics.hasOwnProperty( x ) ){
          this._topics[x].Publish( data );
        }
      }
    }
this.stopped = false;
  }
};
function Mediator() {
if ( !(this instanceof Mediator) ) {
    return new Mediator();
  }else{
    this._topics = new Topic( "" );
  }
};
Mediator.prototype = {
GetTopic: function( namespace ){
    var topic = this._topics,
        namespaceHierarchy = namespace.split( ":" );
if( namespace === "" ){
      return topic;
    }
if( namespaceHierarchy.length > 0 ){
      for( var i = 0, j = namespaceHierarchy.length; i < j; i++ ){
if( !topic.HasTopic( namespaceHierarchy[i]) ){
          topic.AddTopic( namespaceHierarchy[i] );
        }
topic = topic.ReturnTopic( namespaceHierarchy[i] );
      }
    }
return topic;
  },
Subscribe: function( topiclName, fn, options, context ){
  var options = options || {},
      context = context || {},
      topic = this.GetTopic( topicName ),
      sub = topic.AddSubscriber( fn, options, context );
return sub;
},
// Returns a subscriber for a given subscriber id / named function and topic namespace
GetSubscriber: function( identifier, topic ){
  return this.GetTopic( topic || "" ).GetSubscriber( identifier );
},
// Remove a subscriber from a given topic namespace recursively based on
// a provided subscriber id or named function.
Remove: function( topicName, identifier ){
  this.GetTopic( topicName ).RemoveSubscriber( identifier );
},
Publish: function( topicName ){
  var args = Array.prototype.slice.call( arguments, 1),
      topic = this.GetTopic( topicName );
args.push( topic );
this.GetTopic( topicName ).Publish( args );
  }
};
root.Mediator = Mediator;
  Mediator.Topic = Topic;
  Mediator.Subscriber = Subscriber;
// Remember we can pass anything in here. I've passed inwindowto
// attach the Mediator to, but we can just as easily attach it to another
// object if desired.
})( window );
<h1>Chat</h1>
<form id="chatForm">
  <label for="fromBox">Your Name:</label>
  <input id="fromBox" type="text"/>
  <br />
  <label for="toBox">Send to:</label>
  <input id="toBox" type="text"/>
  <br />
  <label for="chatBox">Message:</label>
  <input id="chatBox" type="text"/>
  <button type="submit">Chat</button>
</form>
<div id="chatResult"></div>
$( "#chatForm" ).on( "submit", function(e) {
  e.preventDefault();
// Collect the details of the chat from our UI
  var text = $( "#chatBox" ).val(),
      from = $( "#fromBox" ).val(),
      to = $( "#toBox" ).val();
// Publish data from the chat to the newMessage topic
  mediator.publish( "newMessage" , { message: text, from: from, to: to } );
});
// Append new messages as they come through
function displayChat( data ) {
  var date = new Date(),
      msg = data.from + " said \"" + data.message + "\" to " + data.to;
$( "#chatResult" ).prepend("<p>" + msg + " (" + date.toLocaleTimeString() + ")</p>");
}
// Log messages
function logChat( data ) {
  if ( window.console ) {
    console.log( data );
  }
}
// Subscribe to new chat messages being submitted
// via the mediator
mediator.subscribe( "newMessage", displayChat );
mediator.subscribe( "newMessage", logChat );
// The following will however only work with the more advanced implementation:
function amITalkingToMyself( data ) {
  return data.from === data.to;
}
function iAmClearlyCrazy( data ) {
  $( "#chatResult" ).prepend("<p>" + data.from + " is talking to himself.</p>");
}
mediator.Subscribe( amITalkingToMyself, iAmClearlyCrazy );