Tilbage i januar i år annoncerede jQuery en ny plugins registreringsdatabasen , så nu syntes det som en god tid at skrive en tutorial kombinerer at opbygge et jQuery-plugin med min passion-realtime webteknologi.

Realtime webteknologier gør det virkelig nemt at føje levende indhold til tidligere statiske websider. Levende indhold kan bringe en side i live, beholde brugere og fjerne behovet for at opdatere siden med jævne mellemrum. Realtime opdateringer opnås generelt ved at forbinde til en datakilde, abonnere på de data, du vil tilføje til siden, og derefter opdatere siden som dataene ankommer. Men hvorfor kan dette ikke opnås ved blot at markere en side for at identificere, hvilke data der skal vises, og hvor? Nå, måske kan det!

jQuery's tagline er skrive mindre, gør mere . Taglinjen for jQuery Realtime-plugin, som vi skal opbygge i denne tutorial, vil skrive mindre, gøre realtid.

I denne vejledning opretter vi et jQuery-plugin, der gør det virkelig nemt at tilføje realtids indhold til en side ved blot at tilføje nogle markeringer. For det første dækker vi hvordan du bruger en kaldet tjeneste Pusher at abonnere på realtidsdata. Derefter definerer vi en måde at markere et HTML5-dokument med 'data- *' attributter på en måde, som derefter kan forespørges af vores realtime jQuery-plugin og konverteres til realtime data abonnementer. Endelig opretter vi jQuery-plugin'et, som bruger attributterne til at abonnere på data og øjeblikkeligt viser opdateringer på siden.

Hvis du bare vil dykke lige i du kan se en demo i aktion eller du kan download koden og start hacking.

Pusher basics

Pusher er en hostet service, der gør det nemt at tilføje realtidsindhold og interaktive oplevelser til web- og mobilapps. Her skal vi blot forbinde, abonnere på nogle data og derefter opdatere en side, når dataene kommer ind.

For at demonstrere dette opretter du en fil kaldet 'example.html' og inkluderer Pusher JavaScript-biblioteket fra Pusher CDN. Vi ved, at vi skal bruge jQuery 2.0.0, så vi bør også inkludere det nu:

Creating a realtime jQuery plugin | Webdesigner Depot

Forbinde

Når Pusher JavaScript-biblioteket er medtaget, kan vi oprette forbindelse til Pusher ved at oprette en ny 'Pusher'-forekomst og bestå i en applikationsnøgle. Opret 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:

Lad os se på at skabe den forventede funktionalitet.

Et realtime plugin

Opret først en 'realtime.jquery.js' -fil i 'src' -mappen. Denne fil indeholder pluginfunktionaliteten. Tilføj derefter følgende til filen som udgangspunkt for vores plugin:

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

Vi kan endda teste dette ud nu. I eksemplet / bitcoin / index.html fjerner du eksemplet plugin '

Hvis du opdaterer siden nu, vil du se 'realtime!' logget til JavaScript-konsollen sammen med HTML'en fra '

'element. Dette er godt, da det betyder, at pluginet virker; Vi gennemfører vores plugin-funktionalitet på bordet, der er identificeret af den vælger vi bestod i til jQuery.

pusher_005

jQuery-plugins og tredjepartsbiblioteker

Vores realtime plugin er afhængig af et tredjepartsbibliotek - Pusher JavaScript-biblioteket. For øjeblikket har vi den inkluderet statisk i vores HTML, men vi ønsker ikke at gøre det til et krav om at bruge plugin'et. Så lad os dynamisk indlæse det. jQuery giver mulighed for nemt at gøre dette i form af '.getScript ()' fungere.

Så lad os læse version 2.0 af Pusher JavaScript-biblioteket. Vi læser HTTPS-hosted versionen, så browsere er glade, hvis vores plugin bruges på en side, der serveres over HTTPS (Chrome allerede blokkerer forsøg på at indlæse HTTP-hostede scripts i HTTPS-sider, og Firefox vil gøre i Firefox 23 ). Jeg skal pakke ind i biblioteket i en funktion 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 );}  );} funktion pusherLoaded (script, textStatus) {libraryLoaded = true; console.log ('pusher.min.js indlæst:' + textStatus);} loadPusher (); 

Hvis du genindlæser siden, vil meddelelsen 'pusher.min.js loaded: succes' blive logget til konsollen.

Da vi udvikler det, er det altid godt at have en måde at logge på information, så på dette tidspunkt laver vi en simpel log-funktion, som vi kan bruge, som bare logger på konsollen. Vi bruger dette nu og bruger det også til at logge Pusher events. Den fulde kilde til plugin er nu:

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

Du vil også bemærke, at vi har tildelt 'log'-funktionen til egenskaben' Pusher.log '. Det betyder, at vi kan se den interne Pusher bibliotek logging såvel som vores egne.

Hvornår skal vi forbinde?

På grund af den asynkrone karakter af indlæsningen af ​​biblioteket kan vi ikke garantere, at det vil blive indlæst, når vores plugin bliver kaldt til handling. Desværre gør det tingene lidt mere komplekse end det er ideelt, men vi vil forsøge at løse det så enkelt som muligt.

Vi skal kontrollere for at se om biblioteket har indlæst - dermed 'libraryLoaded' flag - og handle hensigtsmæssigt; hvis biblioteket er indlæst, kan vi forbinde, hvis det ikke har vi brug for at køre udførelsen, indtil det gør det. På grund af dette er det mere fornuftigt kun at oprette Pusher-forekomsten, når vi virkelig har brug for det, hvilket er når vi faktisk ønsker at abonnere på data.

Lad os se på, hvordan vi kan gø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'en hedder, kontrollerer vi feltet 'libraryLoaded' for at se om Pusher JavaScript-biblioteket er blevet indlæst. Hvis det er godt, så går vi, og vi kan abonnere. Hvis det endnu ikke er tilfældet, skal vi opkøbe abonnementerne. Det gør vi ved at trykke på jQuery-samlingen ('els') på et 'ventende' array.

Nu skal du forbinde

Nu da vi ved, at Pusher JavaScript-biblioteket er indlæst, og at siden ønsker at abonnere på data, kan vi oprette vores 'Pusher'-forekomst. Fordi vi kun vil have en 'Pusher' forekomst pr. Side, vil vi følge Singleton mønster og få 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 funktion tager fat i plugin script taggen ved at kigge efter et tag med en 'src' attribut, der slutter med 'jquery.realtime.js' og derefter får værdien af ​​attributten 'data-rt-key'. Det skaber så en ny 'Pusher' instans, der passerer i nøglen. Som diskuteret tidligere skaber en ny "Pusher" -instans en forbindelse til kilden til vores data, der etableres.

Tilmeld

Vi kan nu bruge 'getPusher ()' funktionen når som helst vi ønsker at få adgang til 'Pusher'-forekomsten. I vores tilfælde vil vi bruge det, når vi analyserer elementerne for at bestemme abonnementer.

Opdater pladsholderens 'abonnér' funktion og tilføj yderligere funktioner som 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 );}

Find-funktionen er en hjælpefunktion for at få elementer fra en eksisterende samling, der matcher en given vælger ved hjælp af '.filter()', sammen med alle efterkommere af de elementer, der bruger '.Find()'. Vi bruger denne funktion til at finde elementer, der er markeret for at repræsentere kanalabonnementer ("data-rt-channel" -attributten) og for hver af dem vi derefter kalder 'subscribeChannel'. Denne funktion ekstraherer navnet på den kanal, der skal abonneres på, og bruger værdien ved at kalde 'pusher.subscribe (channelName)' for faktisk at abonnere på kanalen.

Binde

Vi skal derefter finde nogle elementer, der er markeret for at repræsentere hændelser (attributten "data-rt-event") for at 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 hændelseselement finder vi at ringe til vores egen bindingsfunktion, der binder til hændelsen på kanalen ved hjælp af 'channel.bind (eventName, eventHandler)'. Hændelseshåndteringsfunktionen er en lille lukning, som gør det muligt for os at sende dataopdateringen, når den modtages, og hændelseselementet til en 'displayUpdate'-funktion.

Hvis vi kører dette nu, kan vi se fra loggen, at der oprettes en forbindelse, vi finder en kanal og abonnerer på det og finder en begivenhed, der skal binde til.

pusher_006

jQuery realtime markup finder kanal abonnement og begivenhed bindende

Vis opdateringen

Når hændelseshåndteringen kaldes, skal vi finde navnet på hver ejendom på "data" -objektet (f.eks. Sidst, lavt, højt og volumen), der sendes med opdateringen, og finde eventuelle elementer, der er markeret med det pågældende navn.

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 løber over 'data'-objektet og får navnet på hver ejendom. Når vi kender ejendomsnavnet ('propName') kan vi finde de tilknyttede elementer og opdatere deres tekstværdi med den nye dataværdi. For nu vil vi ikke støtte objekter med noget slags hierarki - vi vil kun have et niveau af nøgle- og værdipar.

Hvis du nu opdaterer siden og udløser et arrangement fra Pusher Event Creator, vises de nye data øjeblikkeligt på siden.

Har du arbejdet med en live datatjeneste? Hvilke lektioner lærte du? Lad os vide i kommentarerne.

Fremhævet billede / miniaturebillede, live data billede via Shutterstock.