Bereits im Januar dieses Jahres hat jQuery ein neues angekündigt Plugin-Registrierung Jetzt schien es eine großartige Zeit zu sein, ein Tutorial zu schreiben, das den Aufbau eines jQuery-Plugins mit meiner Leidenschaft kombiniert - Echtzeit-Webtechnologien.

Echtzeit-Web-Technologien machen es einfach, Live-Inhalte zu zuvor statischen Webseiten hinzuzufügen. Live-Inhalte können eine Seite zum Leben erwecken, Benutzer zurückhalten und die regelmäßige Aktualisierung der Seite überflüssig machen. Echtzeit-Updates werden im Allgemeinen durch Verbinden mit einer Datenquelle, Abonnieren der Daten, die Sie der Seite hinzufügen möchten, und anschließendes Aktualisieren der Seite beim Eintreffen der Daten erreicht. Aber warum kann das nicht erreicht werden, indem einfach eine Seite markiert wird, um zu identifizieren, welche Daten angezeigt werden sollen und wo? Nun, vielleicht kann es!

jQuery's Slogan schreibt weniger, mehr . Der Slogan für das jQuery Realtime-Plugin, das wir in diesem Tutorial erstellen werden , wird weniger schreiben, sondern in Echtzeit.

In diesem Tutorial erstellen wir ein jQuery-Plugin, mit dem es wirklich einfach ist, einer Seite Echtzeitinhalt hinzuzufügen, indem einfach ein Markup hinzugefügt wird. Zuerst behandeln wir, wie man einen aufgerufenen Dienst benutzt Pusher Echtzeitdaten abonnieren. Dann definieren wir eine Möglichkeit, ein HTML5-Dokument mit "data- *" - Attributen so zu markieren, dass es von unserem jQuery-Echtzeit-Plugin abgefragt und in Echtzeit-Datenabonnements konvertiert werden kann. Schließlich erstellen wir das jQuery-Plugin, das die Attribute zum Abonnieren von Daten und zum sofortigen Anzeigen von Aktualisierungen auf der Seite verwendet.

Wenn Sie nur direkt tauchen wollen, können Sie Sehen Sie sich eine Demo an in Aktion oder du kannst Lade den Code herunter und fang an zu hacken.

Drücker-Grundlagen

Pusher ist ein gehosteter Dienst, der es einfach macht, Echtzeit-Inhalte und interaktive Erlebnisse für Web- und mobile Apps hinzuzufügen. Hier werden wir uns einfach verbinden, einige Daten abonnieren und dann eine Seite aktualisieren, wenn die Daten eintreffen.

Um dies zu demonstrieren, erstellen Sie eine Datei namens "example.html" und fügen Sie die Pusher-JavaScript-Bibliothek aus dem Pusher-CDN hinzu. Wir wissen, dass wir jQuery 2.0.0 verwenden werden, also sollten wir das jetzt auch hinzufügen:

Creating a realtime jQuery plugin | Webdesigner Depot

Verbinden

Sobald die Pusher-JavaScript-Bibliothek eingebunden wurde, können wir uns mit Pusher verbinden, indem wir eine neue "Pusher" -Instanz erstellen und einen Anwendungsschlüssel übergeben. Erstellen Sie ein zusätzliches '

Note: For the tutorial we’ll use an application key that I’ve provided but for your own applications you’ll need to sign up to Pusher to get your own.

You can check that you’re connected in three different ways. You can do it manually by checking the Pusher Debug Console, if you load the page with the Pusher Debug Console open you’ll see the connection logged. The Pusher JavaScript library provides a log property that you can assign a function to and then you can manually check to make sure a connection has been established by inspecting the browser’s JavaScript console. Or you can check the connection programmatically by monitoring the connection state of the Pusher instance.

pusher_001

The Pusher Debug console

Whatever you choose to do, you’ll now be connected.

Subscribe

Pusher uses the Publish & Subscribe pattern, so to receive data from Pusher you first need to subscribe to it. Pusher uses the term channels when it comes to subscriptions, so let’s subscribe to a channel called ‘test-channel’.

As with connection state, you can check the status of a subscription in a few ways; using the Pusher Debug Console, by checking the output from ‘Pusher.log’ or by binding to the ‘pusher:subscription_succeeded’ event.

pusher_002

Using Pusher.log to log pusher-js library information

Bind to events

Those of you who use jQuery will probably be familiar with the idea of binding to events. jQuery does provide shortcuts for some events (e.g. ‘.onclick( )’) but you can also bind to events using ‘.bind(, )’. Pusher follows this convention and you can bind to events to be informed when something updates; when the connection state changes, when a subscription succeeds or when new application data is received. For this example, and with the realtime plugin, we’re interested primarily in the latter.

Let’s bind to a ‘test-event’ on the channel:

When binding to an event you simply identify the event by name and pass in a reference to a function that will be called when that event occurs (is triggered) on the channel.

If you have a Pusher account you can test that the ‘handleEvent’ function is called by using the Pusher Event Creator; enter ‘test-channel’ as the channel name, ‘test-event’ as the event name and some data (‘{ “some” : “data” }’) into the event data text area and click the submit button. You’ll then see the debug information, along with the data you entered, logged to the JavaScript console.

pusher_003 

Triggering an event from the Pusher Event Creator and logging it in the JavaScript console

Since the realtime jQuery plugin that we’re building doesn’t publish (trigger) data (it just consumes it) we won’t cover that here. But if you’re interested in finding out more checkout the Pusher server docs.

Displaying realtime updates

The next thing to consider is displaying the realtime data updates to the user.

For this we’ll need an idea for a simple application; having worked in finance for a few years I’m generally keen to avoid any type of financial example, but Bitcoin has made it interesting and relevant. So, let’s create a very simple display for showing Bitcoin prices.

Note: We’re going to use some fake data. Let’s make sure this doesn’t result in more Bitcoin panic selling!

First, let’s create some HTML where we’ll display the realtime prices. We can pre-populate the display with prices known at the time the page was loaded:

Bitcoin Fake Prices

LastLowHighVolume
BTC/USD61.157 USD51 USD95.713 USD66271 BTC / 4734629 USD

Let’s update the JavaScript to subscribe to a more appropriately named channel called ‘btc-usd’ and bind to a ‘new-price’ event:

The ‘data’ sent to the ‘handleEvent’ function should also be in a more appropriate format – here’s the JSON:

{"last": "last value","low": "low value","high": "high value","volume": "volume value"}

Now that we know this we can change the ‘handleEvent’ function to update the appropriate cell in the table:

function handleEvent( data ) {var cells = $( '#bitcoin_prices tbody tr td' );cells.eq( 1 ).text( data.last );cells.eq( 2 ).text( data.low );cells.eq( 3 ).text( data.high );cells.eq( 4 ).text( data.volume );}

If you now trigger a ‘new-price’ event on the ‘btc-usd’ channel, using the JSON we defined, the page will update to show the new values.

There are ways of both making this code nicer and, as the page grows to show more data, optimise things. But, we’re going to make it so that realtime data will be added to the page simply by applying markup.

Before we progress, let’s first add a bit of styling to the example. In the ‘’ add the following CSS:

As you can undoubtedly tell, I’m no designer. So please feel free to improve on this.

pusher_004

The “styled” Bitcoin Fake Prices application

Finally, restructure things so we’re set up for building the plugin.

  1. Create an ‘examples’ directory and within it a ‘bitcoin’ directory.
  2. Move the ‘example.html’ file to ‘examples/bitcoin’, rename it ‘index.html’.
  3. Create a ‘src’ directory at the top-level of the project.

The directory structure should now look as follows:

/
examples/
bitcoin/
index.html
src/

We’re now ready to define our realtime markup and build the realtime jQuery plugin.

Realtime markup

The first thing to highlight is that this isn’t a new idea — I worked for a company called Caplin Systems and in 2001 they had a technology known as RTML that let you markup a page so that realtime updates could be applied. The purpose here is to use jQuery to parse the page and then interpret the markup, resulting in subscriptions, event binding and ultimately live content being added to the page.

For our plugin we’ll use HTML5’s data-* attributes. These attributes don’t directly affect the layout or presentation of the page so they’re a great choice for our realtime markup.

The questions we now need to answer about the markup are:

  • Where do we put the Pusher application key?
  • How do we identify what channels should be subscribed to?
  • How do we identify the events that should be bound to on a channel?
  • How do we know what data to display in the page, and where?

The first one is relatively easy. Since we need to include our plugin JavaScript file we can add a ‘data-rt-key’ attribute to the ‘

So, from the script tag you can see we’re going to connect to Pusher using the key identified by ‘data-rt-key’. We’re going to subscribe to the ‘btc-usd’ channel and bind to the ‘new-price’ event. When an event is received we’re going to update the appropriate table cell based on the value indicated by ‘data-rt-value’; if the value of the attribute is ‘last’ then the value of the ‘last’ property is taken from the received ‘data’ object and displayed in the cell.

Hopefully what we are trying to achieve is now pretty clear. Let’s start looking at how to create a jQuery plugin.

jQuery plugin basics

The jQuery plugin creation docs are pretty good so I won’t go into the details here. We’ll simply concentrate on building the functionality that we need in our plugin.

Before we write any code we should consider how we want to use the plugin. The normal way a plugin functions is that you use jQuery to query the page, and then you execute the plugin functionality against the matched elements.

$( 'a' ).toggle();

The above code would find all ‘’ elements and then execute the ‘toggle()’ functionality on them — probably hiding all anchors, so not the most useful example you’ll ever see.

So, let’s say we would want to use the plugin as follows:

Sehen wir uns die erwartete Funktionalität an.

Ein Echtzeit-Plugin

Erstellen Sie zuerst eine Datei 'realtime.jquery.js' im Verzeichnis 'src'. Diese Datei enthält die Plugin-Funktionalität. Dann füge folgendes als Startpunkt unseres Plugins zur Datei hinzu:

( function( $) {$.fn.realtime = function() {console.log( 'realtime!' );console.log( $( this ).html() );}  ;} (jQuery)); 

Das können wir jetzt sogar testen. In 'examples / bitcoin / index.html' das Beispiel-Plugin entfernen '

Wenn Sie die Seite jetzt aktualisieren, sehen Sie "Echtzeit"! in der JavaScript-Konsole zusammen mit dem HTML-Code von der '

' Element. Das ist großartig, weil es bedeutet, dass das Plugin funktioniert. Wir führen unsere Plugin-Funktionalität erfolgreich in der Tabelle aus, die durch den Selektor identifiziert wurde, den wir an jQuery übergeben haben.

pusher_005

jQuery-Plugins und Bibliotheken von Drittanbietern

Unser Echtzeit-Plugin basiert auf einer Drittanbieter-Bibliothek - der Pusher JavaScript-Bibliothek. Im Moment haben wir es statisch in unseren HTML-Code integriert, aber wir möchten das nicht als Voraussetzung für die Verwendung des Plugins verwenden. Lassen Sie uns das also dynamisch laden. jQuery bietet eine einfache Möglichkeit, dies in Form von '.getScript ()' zu tun. Funktion.

Laden wir nun die Version 2.0 der Pusher-JavaScript-Bibliothek. Wir laden die von HTTPS gehostete Version, damit die Browser zufrieden sind, wenn unser Plugin auf einer Seite verwendet wird, die über HTTPS geschaltet wird. Chrome blockiert bereits Versuche, HTTP-gehostete Skripts auf HTTPS-Seiten zu laden Firefox 23 ). Ich werde das Laden der Bibliothek in eine Funktion wie folgt einbinden:

var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {console.log( 'oh oh! ' + exception );}  );} function pusherLoaded (Skript, TextStatus) {libraryLoaded = true; console.log ('pusher.min.js geladen:' + textStatus);} loadPusher (); 

Wenn Sie die Seite neu laden, wird die Meldung "pusher.min.js loaded: success" auf der Konsole geloggt.

Während wir uns entwickeln, ist es immer gut, eine Möglichkeit zu haben, Informationen zu protokollieren, um an dieser Stelle eine einfache 'Protokoll' -Funktion zu erstellen, die wir verwenden können und die sich nur an der Konsole anmeldet. Wir werden das jetzt verwenden und es auch für die Protokollierung von Pusher-Ereignissen verwenden. Die vollständige Quelle des Plugins ist jetzt:

( function( $ ) {function log( msg ) {console.log( msg );}var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {log( 'oh oh! ' + exception );}  );} function pusherLoaded (Skript, TextStatus) {libraryLoaded = true; Pusher.log = log; log ('pusher.min.js geladen:' + textStatus);} $. fn.realtime = function () {log (' Echtzeit! '); log ($ (this) .html ());}; loadPusher ();} (jQuery)); 

Sie werden außerdem feststellen, dass der Eigenschaft 'Pusher.log' die Funktion 'log' zugewiesen wurde. Dies bedeutet, dass wir sowohl die interne Pusher-Bibliothek als auch unsere eigene Protokollierung sehen können.

Wann sollten wir uns verbinden?

Aufgrund der asynchronen Art des Ladens der Bibliothek können wir nicht garantieren, dass sie geladen wurde, wenn unser Plugin in Aktion tritt. Leider macht dies die Dinge ein wenig komplexer als ideal, aber wir werden versuchen, es so einfach wie möglich zu lösen.

Wir müssen prüfen, ob die Bibliothek geladen ist - daher das Flag "libraryLoaded" - und entsprechend handeln; Wenn die Bibliothek geladen ist, können wir eine Verbindung herstellen. Wenn dies nicht der Fall ist, müssen wir die Ausführung in die Warteschlange stellen, bis sie es tut. Aus diesem Grund ist es sinnvoller, die Pusher-Instanz nur dann zu erstellen, wenn sie wirklich benötigt wird. In diesem Fall möchten wir tatsächlich Daten abonnieren.

Schauen wir uns an, wie wir das machen können:

var pending = [];function pusherLoaded( script, textStatus ) {libraryLoaded = true;while( pending.length !== 0 ) {var els = pending.shift();subscribe( els );}}function subscribe( els ) {}$.fn.realtime = function() {var els = this;if( libraryLoaded ) {subscribe( els );}else {pending.push( els );}};

Wenn das Plugin aufgerufen wird, überprüfen wir das Flag 'libraryLoaded', um zu sehen, ob die Pusher-JavaScript-Bibliothek geladen wurde. Wenn es geht, sind wir gut zu gehen und wir können abonnieren. Wenn es noch aussteht, müssen wir die Abonnements in die Warteschlange stellen. Dazu schieben wir die jQuery-Sammlung ('els') auf ein 'pending'-Array.

Jetzt verbinden

Nachdem wir nun wissen, dass die Pusher JavaScript-Bibliothek geladen wurde und die Seite Daten abonnieren möchte, können wir unsere "Pusher" -Instanz erstellen. Da wir nur eine "Pusher" - Instanz pro Seite haben wollen, folgen wir der Singleton-Muster und habe einen 'getPusher ()':

var pusher;function getPusher() {if( pusher === undefined ) {var pluginScriptTag = $("script[src$='jquery.realtime.js']");var appKey = pluginScriptTag.attr("data-rt-key");pusher = new Pusher( appKey );}return pusher;}

Diese Funktion ruft das Plugin-Skript-Tag ab, indem sie nach einem Tag mit dem Attribut 'src' sucht, das mit 'jquery.realtime.js' endet, und erhält dann den Wert des Attributs 'data-rt-key'. Es erstellt dann eine neue "Pusher" -Instanz und gibt den Schlüssel ein. Wie bereits erwähnt, führt die Erstellung einer neuen "Pusher" -Instanz dazu, dass eine Verbindung zur Quelle unserer Daten hergestellt wird.

Abonnieren

Wir können jetzt die 'getPusher ()' Funktion verwenden, wann immer wir auf die 'Pusher'-Instanz zugreifen wollen. In unserem Fall möchten wir es verwenden, wenn wir die Elemente analysieren, um Abonnements zu bestimmen.

Aktualisieren Sie die Platzhalter-Funktion "Abonnieren" und fügen Sie die folgenden zusätzlichen Funktionen hinzu:

function subscribe( els ) {var channelEls = els.find( "*[data-rt-channel]" );log( 'found ' + channelEls.size() + ' channels' );channelEls.each( subscribeChannel );}function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );}function find( els, selector ) {var topLevelEls = els.filter( selector );var childEls = els.find( selector );return topLevelEls.add( childEls );}

Die Funktion 'Suchen' ist eine Hilfsfunktion, um Elemente aus einer vorhandenen Sammlung zu erhalten, die mit einem bestimmten Selektor übereinstimmen '.Filter()', zusammen mit allen Nachkommen der Elemente mit '.finden()'. Wir verwenden diese Funktion, um alle Elemente zu finden, die als Kanalabonnements gekennzeichnet sind (Attribut 'data-rt-channel'), und für jede wird 'subscribeChannel' aufgerufen. Diese Funktion extrahiert den Namen des Kanals, der abonniert werden soll, und verwendet den Wert beim Aufrufen von 'pusher.subscribe (channelName)', um den Kanal tatsächlich zu abonnieren.

Binden

Wir müssen dann alle Elemente finden, die markiert sind, um Ereignisse darzustellen (Attribut 'data-rt-event'), an die gebunden werden soll:

function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );var eventEls = find( el, '*[data-rt-event]' );log( 'found ' + eventEls.size() + ' events' );eventEls.each( function( i, el) {bind( el, channel );} );}function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {}

Für jedes Ereigniselement nennen wir unsere eigene 'bind'-Funktion, die mit' channel.bind (eventName, eventHandler) 'an das Ereignis im Channel bindet. Die Event-Handler-Funktion ist eine kleine Schließung, die es uns ermöglicht, die Datenaktualisierung, wenn sie empfangen wird, und das Ereigniselement an eine 'displayUpdate'-Funktion zu übergeben.

Wenn wir das jetzt ausführen, können wir aus der Protokollierung sehen, dass eine Verbindung aufgebaut wird, wir finden einen Kanal und abonnieren ihn und finden ein Ereignis, an das wir uns binden.

pusher_006

jQuery Realtime Markup, das Kanalabonnement und Ereignisbindung findet

Zeigen Sie das Update an

Wenn der Event-Handler aufgerufen wird, müssen wir den Namen jeder Eigenschaft auf dem Objekt 'data' (z. B. last, low, high und volume) suchen, das mit dem Update gesendet wurde, und alle Elemente finden, die mit diesem Namen markiert sind.

function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {for( var propName in data ) {var value = data[ propName ];var updateEls = find( el, '*[data-rt-value="' + propName + '"]' );log( 'found ' + updateEls.size() + ' "' + propName + '" elements to update' );updateEls.text( value );}}

Wir durchlaufen das Objekt 'data' und erhalten den Namen jeder Eigenschaft. Sobald wir den Eigenschaftsnamen ('propName') kennen, können wir die zugehörigen Elemente finden und ihren Textwert mit dem neuen Datenwert aktualisieren. Im Moment werden wir keine Objekte mit irgendeiner Art von Hierarchie unterstützen - wir wollen nur eine Ebene von Schlüssel- und Wertepaaren.

Wenn Sie nun die Seite aktualisieren und ein Ereignis vom Pusher Event Creator auslösen, werden die neuen Daten sofort auf der Seite angezeigt.

Haben Sie mit einem Live-Datendienst gearbeitet? Welche Lektionen hast du gelernt? Lassen Sie es uns in den Kommentaren wissen.

Ausgewähltes Bild / Vorschaubild, Live-Datenbild über Shutterstock.