Tilbake i januar i år annonserte jQuery en ny plugins register , så nå virket som en flott tid å skrive en opplæring kombinere bygge en jQuery plugin med min lidenskap - realtime web teknologier.

Realtime webteknologier gjør det veldig enkelt å legge til levende innhold på tidligere statiske websider. Levende innhold kan bringe en side i live, beholde brukere og fjerne behovet for å oppdatere siden med jevne mellomrom. Realtime oppdateringer oppnås vanligvis ved å koble til en datakilde, abonnere på dataene du vil legge til på siden og deretter oppdatere siden når dataene kommer. Men hvorfor kan dette ikke oppnås ved å bare merke en side for å identifisere hvilke data som skal vises og hvor? Vel, kanskje det kan!

jQuery's tagline er skrive mindre, gjør mer . Tagline for jQuery Realtime plugin som vi skal bygge i denne opplæringen vil være skrive mindre, gjør realtid.

I denne opplæringen lager vi et jQuery-plugin som gjør det veldig enkelt å legge til realtidsinnhold på en side ved ganske enkelt å legge til noen markering. Først vil vi dekke hvordan du bruker en tjeneste som kalles Pusher å abonnere på realtidsdata. Deretter definerer vi en måte å markere et HTML5-dokument med 'data- *' attributter på, som kan etterspørres av vår realtime jQuery-plugin og konverteres til realtime dataabonnementer. Til slutt skal vi opprette jQuery-pluginet som bruker attributter til å abonnere på data og umiddelbart vise oppdateringer på siden.

Hvis du bare vil dykke rett i du kan se en demonstrasjon i aksjon eller du kan last ned koden og begynne å hacking.

Pusher grunnleggende

Pusher er en hosted tjeneste som gjør det enkelt å legge til realtidsinnhold og interaktive opplevelser til web- og mobilapper. Her skal vi bare koble til, abonnere på noen data og deretter oppdatere en side når dataene kommer inn.

For å demonstrere dette lag en fil som heter 'example.html' og inkludere Pusher JavaScript-biblioteket fra Pusher CDN. Vi vet at vi skal bruke jQuery 2.0.0, så vi bør også inkludere det nå:

Creating a realtime jQuery plugin | Webdesigner Depot

Koble

Når Pusher JavaScript-biblioteket er inkludert, kan vi koble til Pusher ved å opprette en ny "Pusher" -eksempel og sende inn en applikasjonsnøkkel. Lag en ekstra '

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:

La oss se på å skape den forventede funksjonaliteten.

En realtid plugin

Først oppretter du en "realtime.jquery.js" -fil i "src" -katalogen. Denne filen inneholder plugin-funksjonaliteten. Legg deretter følgende til filen som utgangspunkt for pluginet vårt:

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

Vi kan til og med teste dette ut nå. I eksempler / bitcoin / index.html fjerner du eksemplet plugin '

Hvis du oppdaterer siden, vil du se "realtime!" logget til JavaScript-konsollen sammen med HTML fra '

'element. Dette er flott som det betyr at pluginet fungerer; Vi har vellykket utført plugin-funksjonaliteten på bordet identifisert av selgeren vi passerte inn i jQuery.

pusher_005

jQuery-plugins og tredjepartsbiblioteker

Vårt realtime-plugin er avhengig av et tredjepartsbibliotek - Pusher JavaScript-biblioteket. For øyeblikket har vi den inkludert statisk i HTML, men vi vil ikke gjøre det til et krav om å bruke plugin. Så la oss dynamisk laste den. jQuery gir en måte å enkelt gjøre dette på i form av '.getScript ()' funksjon.

Så la oss laste versjon 2.0 av Pusher JavaScript-biblioteket. Vi laster inn HTTPS-vertversjonen slik at nettleserne er glade hvis pluginet vårt brukes på en side som vises over HTTPS (Chrome blokkerer allerede forsøk på å laste HTTP-hostede skript i HTTPS-sider, og Firefox vil gjøre det i Firefox 23 ). Jeg skal pakke inn biblioteket i en funksjon som følger:

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 );}  );} funksjon pusherLoaded (script, textStatus) {libraryLoaded = true; console.log ('pusher.min.js lastet:' + textStatus);} loadPusher (); 

Hvis du oppdaterer siden, vil meldingen "pusher.min.js loaded: suksess" bli logget til konsollen.

Når vi utvikler det, er det alltid godt å ha en måte å logge på informasjon, så nå kan vi lage en enkel loggfunksjon som vi kan bruke som bare logger på konsollen. Vi bruker dette nå, og bruker det også til å logge Pusher-hendelser. Den fullstendige kilden til plugin er nå:

( 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 );}  );} funksjon pusherLoaded (script, textStatus) {libraryLoaded = true; Pusher.log = log; log ('pusher.min.js lastet:' + textStatus);} $. fn.realtime = funksjon () {log realtime! '); logg ($ (dette) .html ());}; loadPusher ();} (jQuery)); 

Du vil også legge merke til at vi har tildelt loggfunksjonen til egenskapen 'Pusher.log'. Dette betyr at vi kan se den interne Pusher biblioteket logging så vel som vår egen.

Når skal vi koble?

På grunn av den asynkrone beskaffenheten av å laste inn biblioteket, kan vi ikke garantere at det vil bli lastet når pluginet blir kalt til handling. Dessverre gjør dette tingene litt mer komplekse enn det er ideelt, men vi vil prøve å løse det på så enkelt måte som mulig.

Vi må sjekke for å se om biblioteket har lastet - dermed "libraryLoaded" flagget - og handle riktig; hvis biblioteket har lastet inn, kan vi koble til, hvis det ikke har vi trenger å kjøre kjøringen til den gjør det. På grunn av dette er det mer fornuftig å bare opprette Pusher-forekomsten når vi virkelig trenger det, noe som er når vi faktisk ønsker å abonnere på data.

La oss se på hvordan vi kan gjøre det:

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 );}};

Når plugin er kalt, kontrollerer du 'libraryLoaded' flagg for å se om Pusher JavaScript-biblioteket er lastet inn. Hvis det er bra, går vi, og vi kan abonnere. Hvis det fortsatt er ventet, må vi kø opp abonnementene. Vi gjør dette ved å trykke på jQuery-samlingen ('els') på et "ventende" utvalg.

Nå, koble til

Nå som vi vet at Pusher JavaScript-biblioteket har lastet inn og at siden ønsker å abonnere på data, kan vi opprette vår "Pusher" -eksempel. Fordi vi bare vil ha en "Pusher" -eksempel per side, skal vi følge Singleton mønster og ha en '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;}

Denne funksjonen tar tak i plugin script taggen ved å lete etter en tag med et "src" attributt som ender med 'jquery.realtime.js', og får deretter verdien av attributten 'data-rt-key'. Det oppretter så en ny "Pusher" -eksempel, som går forbi nøkkelen. Som diskutert tidligere, oppretter en ny "Pusher" -eksempel resulterer i en forbindelse til kilden til at våre data blir etablert.

Abonnere

Vi kan nå bruke 'getPusher ()' -funksjonen når som helst vi ønsker å få tilgang til 'Pusher'-forekomsten. I vårt tilfelle vil vi bruke det når vi analyserer elementene for å bestemme abonnementer.

Oppdater plassholderen 'abonnere' -funksjonen og legg til tilleggsfunksjonene som er vist nedenfor:

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 );}

Funksjonen "finn" er en funksjon for å få elementer fra en eksisterende samling som samsvarer med en gitt väljare ved hjelp av '.filter()', sammen med noen etterkommere av elementene som bruker '.finne()'. Vi bruker denne funksjonen til å finne noen elementer som er merket for å representere kanalabonnementer ('data-rt-channel' attributt) og for hver vi kaller "abonnerekanal". Denne funksjonen trekker ut navnet på kanalen som skal abonneres på, og bruker verdien til å ringe 'pusher.subscribe (channelName)' for å faktisk abonnere på kanalen.

Binde

Vi må da finne noen elementer som er merket for å representere hendelser ("data-rt-event" attributt) for å være bundet til:

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 ) {}

For hvert hendelseelement finner vi ring vår egen "bind" -funksjon som binder til hendelsen på kanalen ved hjelp av "channel.bind (eventName, eventHandler) '. Hendelseshåndteringsfunksjonen er en liten nedleggelse som tillater oss å sende dataoppdateringen, når den mottas, og hendelseselementet til en "displayUpdate" -funksjon.

Hvis vi kjører dette nå, kan vi se fra loggen at en tilkobling er opprettet, vi finner en kanal og abonnerer på den, og finner en begivenhet å binde seg til.

pusher_006

jQuery realtime markup finne kanal abonnement og hendelsen bindende

Vis oppdateringen

Når hendelsesbehandleren er kalt, må vi finne navnet på hver eiendom på "data" -objektet (for eksempel sist, lavt, høyt og volum) som sendes med oppdateringen, og finne elementer som er merket med det navnet.

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 );}}

Vi slår over 'data'-objektet og får navnet på hver eiendom. Når vi kjenner eiendomsnavnet ('propName'), kan vi finne de tilknyttede elementene og oppdatere tekstverdien med den nye dataværdi. For nå skal vi ikke støtte objekter med noe slags hierarki - vi vil bare ha et nivå av nøkkel- og verdipar.

Hvis du oppdaterer siden nå og utløser en hendelse fra Pusher Event Creator, blir de nye dataene umiddelbart vist på siden.

Har du jobbet med en live datatjeneste? Hvilke leksjoner lærte du? Gi oss beskjed i kommentarene.

Utvalgt bilde / miniatyrbilde, live data bilde via Shutterstock.