Τον Ιανουάριο του τρέχοντος έτους η jQuery ανακοίνωσε νέα plugins registry , έτσι τώρα φαινόταν σαν μια μεγάλη στιγμή για να γράψω ένα σεμινάριο που συνδυάζει την οικοδόμηση ενός plugin jQuery με το πάθος μου - τεχνολογίες web πραγματικού χρόνου.

Οι τεχνολογίες ιστού σε πραγματικό χρόνο καθιστούν πραγματικά εύκολο το να προσθέσετε ζωντανό περιεχόμενο σε παλιές στατικές ιστοσελίδες. Το ζωντανό περιεχόμενο μπορεί να φέρει μια σελίδα ζωντανή, να διατηρεί τους χρήστες και να αφαιρεί την ανάγκη ανάκτησης της σελίδας περιοδικά. Οι ενημερώσεις σε πραγματικό χρόνο επιτυγχάνονται γενικά με τη σύνδεση με μια πηγή δεδομένων, την εγγραφή στα δεδομένα που θέλετε να προσθέσετε στη σελίδα και την ενημέρωση της σελίδας καθώς φθάνουν τα δεδομένα. Αλλά γιατί δεν μπορεί να επιτευχθεί αυτό με την απλή επισήμανση μιας σελίδας για να προσδιοριστούν τα δεδομένα που πρέπει να παρουσιαστούν και πού; Λοιπόν, ίσως μπορεί!

Η ετικέτα του jQuery γράφει λιγότερα, κάνει περισσότερα . Η ετικέτα για την προσθήκη jQuery Realtime που πρόκειται να δημιουργήσουμε σε αυτό το σεμινάριο θα είναι λιγότερη εγγραφή, δεν γίνεται σε πραγματικό χρόνο.

Σε αυτό το σεμινάριο θα δημιουργήσουμε ένα plugin jQuery που καθιστά πραγματικά εύκολη την προσθήκη περιεχομένου σε πραγματικό χρόνο σε μια σελίδα προσθέτοντας απλά κάποια σήμανση. Πρώτον, θα καλύψουμε τον τρόπο χρήσης μιας υπηρεσίας που ονομάζεται Ωθών να εγγραφείτε σε δεδομένα σε πραγματικό χρόνο. Στη συνέχεια, θα ορίσουμε έναν τρόπο σήμανσης ενός εγγράφου HTML5 με χαρακτηριστικά 'data- *' κατά τρόπο που στη συνέχεια θα μπορεί να ερωτηθεί από το πραγματικό plugin jQuery και να μετατραπεί σε συνδρομές δεδομένων πραγματικού χρόνου. Τέλος, θα δημιουργήσουμε το plugin jQuery το οποίο θα χρησιμοποιεί τα χαρακτηριστικά για να εγγραφεί σε δεδομένα και θα εμφανίζει άμεσα τις ενημερώσεις μέσα στη σελίδα.

Εάν απλά θέλετε να βουτήξετε κατ 'ευθείαν σε εσάς μπορείτε προβάλετε μια επίδειξη σε δράση ή μπορείτε κατεβάστε τον κώδικα και ξεκινήστε την πειρατεία.

Βασικά στοιχεία του Pusher

Ο Pusher είναι μια φιλοξενούμενη υπηρεσία που διευκολύνει την προσθήκη περιεχομένου σε πραγματικό χρόνο και διαδραστικών εμπειριών σε εφαρμογές ιστού και κινητής τηλεφωνίας. Εδώ πρόκειται απλώς να συνδεθείτε, να εγγραφείτε σε κάποια δεδομένα και στη συνέχεια να ενημερώσετε μια σελίδα όταν τα δεδομένα έρχονται.

Για να το δείξετε, δημιουργήστε ένα αρχείο που ονομάζεται 'example.html' και συμπεριλάβετε τη βιβλιοθήκη JavaScript Pusher από το CDN Pusher. Γνωρίζουμε ότι πρόκειται να χρησιμοποιήσουμε το jQuery 2.0.0, οπότε θα πρέπει να το συμπεριλάβουμε και τώρα:

Creating a realtime jQuery plugin | Webdesigner Depot

Συνδέω-συωδεομαι

Μόλις συμπεριληφθεί η βιβλιοθήκη JavaScript Pusher, μπορούμε να συνδεθούμε με τον Pusher δημιουργώντας μια νέα παρουσία Pusher και περνώντας σε ένα κλειδί εφαρμογής. Δημιουργήστε μια πρόσθετη '

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:

Ας δούμε τη δημιουργία της αναμενόμενης λειτουργικότητας.

Ένα plugin σε πραγματικό χρόνο

Αρχικά, δημιουργήστε ένα αρχείο 'realtime.jquery.js' μέσα στον κατάλογο 'src'. Αυτό το αρχείο θα περιέχει τη λειτουργία plugin. Στη συνέχεια, προσθέστε τα εξής στο αρχείο ως σημείο εκκίνησης της προσθήκης μας:

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

Μπορούμε ακόμη να το δοκιμάσουμε τώρα. Στο 'παραδείγματα / bitcoin / index.html' αφαιρέστε το παράδειγμα plugin '

Αν ανανεώσετε τη σελίδα τώρα θα δείτε "σε πραγματικό χρόνο!" συνδεδεμένο στην κονσόλα JavaScript μαζί με το HTML από το "

' στοιχείο. Αυτό είναι μεγάλο, καθώς σημαίνει ότι το plugin λειτουργεί. εκτελέσαμε επιτυχώς τη λειτουργία plugin μας στο τραπέζι που προσδιορίστηκε από τον επιλογέα που περάσαμε στο jQuery.

pusher_005

Προσθήκες jQuery και βιβλιοθήκες τρίτου μέρους

Το πραγματικό μας plugin βασίζεται σε μια βιβλιοθήκη τρίτου μέρους - τη βιβλιοθήκη JavaScript Pusher. Προς το παρόν έχουμε συμπεριληφθεί στατικά μέσα στην HTML, αλλά δεν θέλουμε να κάνουμε αυτή την απαίτηση να χρησιμοποιήσουμε το plugin. Ας το φορτώσουμε δυναμικά. Το jQuery παρέχει έναν τρόπο να το κάνετε εύκολα με τη μορφή του .getScript () λειτουργία.

Έτσι, ας φορτώσουμε την έκδοση 2.0 της βιβλιοθήκης JavaScript του Pusher. Θα φορτώσουμε την φιλοξενούμενη έκδοση HTTPS έτσι ώστε τα προγράμματα περιήγησης να είναι ευτυχισμένα αν το plugin μας χρησιμοποιείται σε μια σελίδα που προβάλλεται μέσω HTTPS (το Chrome αποκλείει ήδη απόπειρες φόρτωσης σερβοποιημένων σε HTTP σεναρίων σε σελίδες HTTPS και το Firefox θα κάνει Firefox 23 ). Πάω να περιτυλίξω τη φόρτωση της βιβλιοθήκης σε μια λειτουργία ως εξής:

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 );}  );} λειτουργία pushherLoaded (script, textStatus) {libraryLoaded = true; console.log ('φορτωτής pusher.min.js:' + textStatus)}} loadPusher (); 

Εάν επαναλάβετε τη φόρτωση της σελίδας, το μήνυμα 'pusher.min.js loaded: success' θα καταγραφεί στην κονσόλα.

Καθώς αναπτύσσουμε, είναι πάντα καλό να έχουμε έναν τρόπο να καταγράψουμε τις πληροφορίες έτσι ώστε σε αυτό το σημείο ας δημιουργήσουμε μια απλή λειτουργία 'log' που μπορούμε να χρησιμοποιήσουμε η οποία μόλις καταγράφει στην κονσόλα. Θα το χρησιμοποιήσουμε τώρα και θα το χρησιμοποιήσουμε και για την καταγραφή συμβάντων Pusher. Η πλήρης πηγή του plugin είναι τώρα:

( 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 (script, textStatus) {libraryLoaded = true; Pusher.log = log; log ('pushher.min.js φορτωμένο:' + textStatus) realtime! ') · log ($ (this) .html ());}; loadPusher ();} (jQuery)); 

Θα παρατηρήσετε επίσης ότι έχουμε αναθέσει τη λειτουργία 'log' στην ιδιότητα 'Pusher.log'. Αυτό σημαίνει ότι μπορούμε να δούμε την εσωτερική βιβλιοθήκη Pusher καθώς και τη δική μας.

Πότε πρέπει να συνδεθούμε;

Λόγω της ασύγχρονης φύσης της φόρτωσης της βιβλιοθήκης, δεν μπορούμε να εγγυηθούμε ότι θα φορτωθεί όταν ενεργοποιηθεί το plugin μας. Δυστυχώς αυτό κάνει τα πράγματα λίγο πιο περίπλοκα από ό, τι είναι ιδανικό, αλλά θα προσπαθήσουμε να τα λύσουμε με έναν όσο το δυνατόν απλούστερο τρόπο.

Πρέπει να ελέγξουμε αν έχει φορτωθεί η βιβλιοθήκη - εξ ου και η σημαία «libraryLoaded» - και να ενεργήσουμε σωστά. αν η βιβλιοθήκη έχει φορτωθεί μπορούμε να συνδεθούμε, αν δεν έχει ανάγκη να εκτελέσουμε την ουρά μέχρι την εκτέλεση. Εξαιτίας αυτού, είναι πιο λογικό να δημιουργούμε μόνο την περίπτωση Pusher όταν την χρειαζόμαστε πραγματικά, δηλαδή όταν θέλουμε πραγματικά να εγγραφούμε σε δεδομένα.

Ας δούμε πώς μπορούμε να το κάνουμε αυτό:

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

Όταν καλείται το plugin, ελέγξουμε τη σημαία 'libraryLoaded' για να δούμε αν έχει φορτωθεί η βιβλιοθήκη JavaScript Pusher. Εάν έχουμε καλή επιτυχία και μπορούμε να εγγραφούμε. Εάν εξακολουθεί να βρίσκεται σε εκκρεμότητα, τότε πρέπει να εκτελέσουμε τις ουρές των συνδρομών. Το κάνουμε αυτό πιέζοντας τη συλλογή jQuery ('els') σε μια 'εκκρεμούσα' συστοιχία.

Τώρα, συνδεθείτε

Τώρα που γνωρίζουμε ότι η βιβλιοθήκη JavaScript Pusher έχει φορτωθεί και ότι η σελίδα θέλει να εγγραφεί σε δεδομένα που μπορούμε να δημιουργήσουμε το παράδειγμα μας Pusher. Επειδή θέλουμε μόνο ένα παράδειγμα Pusher ανά σελίδα, θα ακολουθήσουμε το Σχέδιο Singleton και έχετε ένα '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;}

Αυτή η λειτουργία αρπάζει την ετικέτα script plugin αναζητώντας μια ετικέτα με ένα χαρακτηριστικό 'src' που τελειώνει με το 'jquery.realtime.js' και έπειτα παίρνει την τιμή του χαρακτηριστικού 'data-rt-key'. Δημιουργεί στη συνέχεια ένα νέο παράδειγμα Pusher, περνώντας στο κλειδί. Όπως αναφέρθηκε προηγουμένως, η δημιουργία μιας νέας παρουσίας "Pusher" οδηγεί σε μια σύνδεση με την πηγή των δεδομένων μας που δημιουργούνται.

Εγγραφείτε

Τώρα μπορούμε να χρησιμοποιήσουμε τη λειτουργία 'getPusher ()' κάθε φορά που θέλουμε να έχουμε πρόσβαση στην παράθεση 'Pusher'. Στην περίπτωσή μας, θέλουμε να το χρησιμοποιήσουμε όταν αναλύουμε τα στοιχεία για τον προσδιορισμό των συνδρομών.

Ενημερώστε τη συνάρτηση κράτησης θέσης "placeholder" και προσθέστε τις πρόσθετες λειτουργίες που εμφανίζονται παρακάτω:

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

Η λειτουργία 'εύρεση' είναι μια συνάρτηση χρησιμότητας για την λήψη οποιωνδήποτε στοιχείων από μια υπάρχουσα συλλογή που ταιριάζει με ένα συγκεκριμένο επιλογέα χρησιμοποιώντας '.φίλτρο()', μαζί με οποιονδήποτε απόγονο των στοιχείων που χρησιμοποιούν '.εύρημα()'. Χρησιμοποιούμε αυτή τη λειτουργία για να βρούμε όλα τα στοιχεία που έχουν επισημανθεί για να αντιπροσωπεύουν συνδρομές καναλιών (χαρακτηριστικό 'data-rt-channel') και για καθένα από αυτά καλούμε "subscribeChannel". Αυτή η λειτουργία εξάγει το όνομα του καναλιού προς εγγραφή και χρησιμοποιεί την τιμή στην κλήση 'pushher.subscribe (channelName)' για να εγγραφεί πραγματικά στο κανάλι.

Δένω

Στη συνέχεια, πρέπει να βρούμε όλα τα στοιχεία που έχουν επισημανθεί για να αντιπροσωπεύουν συμβάντα (χαρακτηριστικό 'data-rt-event') που δεσμεύεται:

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

Για κάθε στοιχείο συμβάντος που βρίσκουμε, ονομάζουμε τη δική μας λειτουργία "δέσμευσης" που συνδέεται με το συμβάν στο κανάλι χρησιμοποιώντας το "channel.bind (eventName, eventHandler)". Η λειτουργία χειρισμού συμβάντων είναι ένα μικρό κλείσιμο το οποίο μας επιτρέπει να περάσουμε την ενημέρωση των δεδομένων, όταν παραληφθεί, και το στοιχείο συμβάντος σε μια λειτουργία 'displayUpdate'.

Αν τρέξουμε αυτό τώρα μπορούμε να δούμε από την καταγραφή ότι μια σύνδεση είναι εγκατεστημένη, βρίσκουμε ένα κανάλι και να εγγραφείτε σε αυτό, και να βρούμε ένα γεγονός που να δεσμεύει.

pusher_006

jQuery σε πραγματικό χρόνο εύρεση εγγραφής καναλιών και δέσμευση συμβάντων

Εμφάνιση της ενημερωμένης έκδοσης

Όταν ο χειριστής συμβάντων καλείται, πρέπει να βρούμε το όνομα κάθε ιδιότητας στο αντικείμενο "δεδομένα" (π.χ. τελευταίο, χαμηλό, υψηλό και όγκο) που αποστέλλεται με την ενημέρωση και να βρει στοιχεία που έχουν επισημανθεί με αυτό το όνομα.

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

Βγάζουμε το αντικείμενο 'data' και παίρνουμε το όνομα κάθε ιδιότητας. Μόλις γνωρίζουμε το όνομα της ιδιότητας ('propName') μπορούμε να βρούμε τα συναφή στοιχεία και να ενημερώσουμε την τιμή κειμένου τους με τη νέα τιμή δεδομένων. Προς το παρόν δεν πρόκειται να υποστηρίξουμε αντικείμενα με οποιαδήποτε ιεραρχία - θέλουμε απλά ένα επίπεδο ζευγών κλειδιών και αξιών.

Αν τώρα ανανεώσετε τη σελίδα και ενεργοποιήσετε ένα συμβάν από τον Δημιουργό συμβάντων Pusher, τα νέα δεδομένα θα εμφανιστούν άμεσα στη σελίδα.

Έχετε συνεργαστεί με μια υπηρεσία ζωντανής μετάδοσης δεδομένων; Ποια μαθήματα μάθατε; Ενημερώστε μας στα σχόλια.

Προτεινόμενη εικόνα / μικρογραφία, ζωντανή εικόνα δεδομένων μέσω Shutterstock.