Tillbaka i januari i år meddelade jQuery ett nytt plugins register , så nu verkade det som en bra tid att skriva en handledning som kombinerar att bygga ett jQuery-plugin med min passion-webbtestteknik.

Realtids webbteknik gör det väldigt enkelt att lägga till levande innehåll på tidigare statiska webbsidor. Levande innehåll kan ge en sida levande, behålla användare och ta bort behovet av att uppdatera sidan regelbundet. Realtidsuppdateringar uppnås vanligtvis genom att ansluta till en datakälla, prenumerera på de data du vill lägga till på sidan och sedan uppdatera sidan när data kommer fram. Men varför kan det inte uppnås genom att bara markera en sida för att identifiera vilka uppgifter som ska visas och var? Jo kanske det kan!

jQuery's tagline är skriv mindre, gör mer . Taglinjen för jQuery Realtime-plugin som vi ska bygga i den här handledningen kommer att skrivas mindre, gör realtid.

I den här handledningen skapar vi ett jQuery-plugin som gör det väldigt enkelt att lägga till realtidsinnehåll på en sida genom att helt enkelt lägga till en viss markering. Först täcker vi hur du använder en tjänst som heter Pusher att prenumerera på realtidsdata. Då ska vi definiera ett sätt att markera ett HTML5-dokument med attributen "data- *" på ett sätt som sedan kan frågas av vårt realtime jQuery-plugin och konverteras till realtidsdataabonnemang. Slutligen skapar vi pluginprogrammet jQuery som använder attributen för att prenumerera på data och direkt visar uppdateringar på sidan.

Om du bara vill dyka rakt i du kan visa en demo i aktion eller du kan ladda ner koden och börja hacka.

Pusher basics

Pusher är en värdtjänst som gör det enkelt att lägga till realtidsinnehåll och interaktiva upplevelser för webb- och mobilappar. Här kommer vi helt enkelt att ansluta, prenumerera på vissa data och sedan uppdatera en sida när data kommer in.

För att visa detta skapar du en fil som heter "example.html" och inkluderar Pusher JavaScript-biblioteket från Pusher CDN. Vi vet att vi ska använda jQuery 2.0.0 så att vi också bör inkludera det nu:

Creating a realtime jQuery plugin | Webdesigner Depot

Ansluta

När Pusher JavaScript-biblioteket har inkluderats kan vi ansluta till Pusher genom att skapa en ny "Pusher" -instans och passera i en applikationsnyckel. Skapa ytterligare ett "

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:

Låt oss se på att skapa den förväntade funktionaliteten.

Ett realtid plugin

Skapa först en "realtime.jquery.js" -fil i katalogen "src". Den här filen innehåller pluginfunktionen. Lägg sedan till följande i filen som utgångspunkt för vårt plugin:

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

Vi kan även testa detta ut nu. I "exempel / bitcoin / index.html" tar du bort exemplet plugin "

Om du uppdaterar sidan nu ser du "realtime!" loggad till JavaScript-konsolen tillsammans med HTML från "

"element. Det här är bra eftersom det betyder att pluginet fungerar; Vi genomför framgångsrikt vår pluginfunktionalitet på bordet identifierad av väljaren vi skickade in till jQuery.

pusher_005

jQuery-plugins och tredje partsbibliotek

Vårt realtime-plugin är beroende av ett tredje partibibliotek - Pusher JavaScript-biblioteket. För tillfället har vi den inkluderat statiskt i vår HTML, men vi vill inte göra det som ett krav att använda plugin. Så, låt oss ladda det dynamiskt. jQuery ger ett sätt att enkelt göra detta i form av ".getScript ()" fungera.

Så, låt oss ladda version 2.0 av Pusher JavaScript-biblioteket. Vi laddar HTTPS-värdversionen så att webbläsare är glada om vårt plugin används på en sida som serveras via HTTPS (Chrome blockerar redan försök att ladda HTTP-värdskript i HTTPS-sidor och Firefox kommer att göra i Firefox 23 ). Jag ska pakka in biblioteket i en funktion enligt följande:

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 laddade:' + textStatus);} loadPusher (); 

Om du laddar om sidan laddas meddelandet "pusher.min.js: success" loggas till konsolen.

När vi utvecklar är det alltid bra att ha ett sätt att logga information så att vi nu kan skapa en enkel loggfunktion som vi kan använda som loggar bara till konsolen. Vi använder det här nu och använder det också för att logga Pusher-händelser. Den fullständiga källan till plugin är 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 laddad:' + textStatus);} $. fn.realtime = function () {log realtime! '); log ($ (this). html ());}; loadPusher ();} (jQuery)); 

Du kommer också märka att vi har tilldelat loggen till egenskapen "Pusher.log". Det betyder att vi kan se det interna Pusher-bibliotekets loggning såväl som vårt eget.

När ska vi ansluta?

På grund av den asynkrona naturen att ladda biblioteket kan vi inte garantera att det kommer att vara laddat när vår plugin kallas till handling. Tyvärr gör det lite mer komplicerat än det är idealiskt men vi försöker lösa det så enkelt som möjligt.

Vi måste kontrollera om biblioteket har laddat - därmed "libraryLoaded" flaggan - och agera på lämpligt sätt; om biblioteket har laddats kan vi ansluta, om det inte behöver vi köera körningen tills det gör det. På grund av detta är det mer meningsfullt att bara skapa Pusher-instansen när vi verkligen behöver det, vilket är när vi faktiskt vill prenumerera på data.

Låt oss se hur vi kan göra 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 heter kallas vi på 'libraryLoaded' flaggan för att se om Pusher JavaScript-biblioteket har laddats. Om det har vi bra att gå och vi kan prenumerera. Om det fortfarande är så måste vi köra upp prenumerationerna. Vi gör detta genom att trycka på jQuery-samlingen ("els") på en "väntande" matris.

Anslut nu

Nu när vi vet att Pusher JavaScript-biblioteket har laddat och att sidan vill prenumerera på data kan vi skapa vår "Pusher" -instans. Eftersom vi bara vill ha en "Pusher" -exempel per sida ska vi följa Singleton mönster och 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;}

Den här funktionen tar tag i plugin-skripttaggen genom att leta efter en tagg med attributet "src" som slutar med "jquery.realtime.js" och får sedan värdet på attributet "data-rt-key". Det skapar sedan en ny "Pusher" -instans, som passerar in i nyckeln. Som diskuterats tidigare skapar en ny "Pusher" -förekomst en koppling till källan för att vår data etableras.

Prenumerera

Vi kan nu använda funktionen getPusher () när vi vill komma åt "Pusher" -förekomsten. I vårt fall vill vi använda det när vi analyserar elementen för att bestämma prenumerationer.

Uppdatera platshållaren "prenumerera" -funktionen och lägg till ytterligare funktioner som visas nedan:

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

Sökfunktionen är en nyttafunktion för att få några element från en befintlig samling som matchar en given väljare med '.filtrera()', tillsammans med några efterkommande av de element som använder '.hitta()'. Vi använder den här funktionen för att hitta några element som är markerade för att representera kanalabonnemang ("data-rt-channel" -attribut) och för varje vi kallar sedan "subscribeChannel". Den här funktionen extraherar namnet på den kanal som ska prenumereras på och använder värdet för att ringa "pusher.subscribe (channelName)" för att faktiskt prenumerera på kanalen.

Binda

Vi måste sedan hitta några element som är markerade för att representera händelser (attributet "data-rt-event") som ska bindas till:

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 varje händelseelement finner vi kalla vår egen bindningsfunktion som binder till händelsen på kanalen med hjälp av "channel.bind (eventName, eventHandler)". Funktionshanteringsfunktionen är en liten stängning som gör det möjligt för oss att skicka datauppdateringen, när den mottas, och händelseelementet till en "displayUpdate" -funktion.

Om vi ​​kör detta nu kan vi se från loggningen att en anslutning är etablerad, vi hittar en kanal och prenumererar på den och hittar en händelse att binda till.

pusher_006

jQuery realtime markup hitta kanal abonnemang och händelse bindande

Visa uppdateringen

När händelsehanteraren heter, måste vi hitta namnet på varje egendom på objektdatobjektet (t.ex. sista, låga, höga och volymer) som skickas med uppdateringen och hitta några element som är markerade med det namnet.

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 över "data" -objektet och får namnet på varje egendom. När vi väl vet egenskapsnamnet ("propName") kan vi hitta de associerade elementen och uppdatera deras textvärde med det nya datavärdet. För tillfället kommer vi inte att stödja objekt med någon form av hierarki - vi vill bara ha en nivå av nyckel- och värdepar.

Om du nu uppdaterar sidan och utlöser en händelse från Pusher Event Creator, visas de nya uppgifterna direkt på sidan.

Har du arbetat med en levande datatjänst? Vilka lektioner lärde du dig? Låt oss veta i kommentarerna.

Utvalda bild / miniatyrbild, levande data bild via Shutterstock.