مرة أخرى في يناير من هذا العام أعلن jQuery جديدة سجل المكونات الإضافية لذلك بدا الآن وكأنه وقت رائع لكتابة برنامج تعليمي يجمع بين إنشاء إضافة jQuery وشغفي - تقنيات الويب في الوقت الفعلي.

تعمل تقنيات الويب في الوقت الفعلي على تسهيل إضافة محتوى مباشر إلى صفحات ويب ثابتة مسبقًا. يمكن أن يؤدي المحتوى المباشر إلى عرض صفحة على قيد الحياة ، والاحتفاظ بالمستخدمين وإزالة الحاجة إليها لتحديث الصفحة بشكل دوري. تتحقق التحديثات في الوقت الفعلي عمومًا عن طريق الاتصال بمصدر للبيانات والاشتراك في البيانات التي تريد إضافتها إلى الصفحة ثم تحديث الصفحة عند وصول البيانات. ولكن لماذا لا يمكن تحقيق ذلك من خلال ترميز صفحة لتحديد البيانات التي يجب عرضها وأين؟ حسنا ، ربما يمكن!

شعار jQuery هو كتابة أقل ، والقيام بالمزيد . سيتم كتابة سطر الوصف لمكوّن jQuery Realtime الذي سننشئه في هذا البرنامج التعليمي بشكل أقل ، ونفعل الوقت الفعلي.

في هذا البرنامج التعليمي ، سننشئ مكون jQuery الإضافي الذي يجعل من السهل بالفعل إضافة محتوى الوقت الفعلي إلى صفحة عن طريق إضافة بعض العلامات. أولاً ، سنتناول كيفية استخدام خدمة تسمى انتهازي للاشتراك في بيانات الوقت الفعلي. ثم سنحدد طريقة لوضع مستند HTML5 مع سمات "data- *" بطريقة يمكن عندئذ الاستعلام عنها من خلال المكون الإضافي jQuery في الوقت الفعلي وتحويلها إلى اشتراكات في الوقت الفعلي للبيانات. وأخيرًا ، سننشئ المكون الإضافي jQuery الذي سيستخدم السمات للاشتراك في البيانات وعرض التحديثات على الفور داخل الصفحة.

إذا كنت فقط تريد الغوص مباشرة في يمكنك عرض تجريبي في العمل أو يمكنك تحميل الكود والبدء في القرصنة.

أساسيات انتهازي

Pusher هي خدمة مستضافة تسهّل إضافة محتوى الوقت الفعلي والخبرات التفاعلية إلى تطبيقات الويب والجوّال. سنقوم هنا ببساطة بالاتصال والاشتراك في بعض البيانات ثم تحديث الصفحة عندما تأتي البيانات.

لشرح ذلك ، قم بإنشاء ملف يسمى 'example.html' وقم بتضمين مكتبة Pusher JavaScript من Pusher CDN. نحن نعلم أننا سنستخدم jQuery 2.0.0 لذا يجب علينا تضمين ذلك الآن:

Creating a realtime jQuery plugin | Webdesigner Depot

الاتصال

بعد تضمين مكتبة Pusher JavaScript ، يمكننا الاتصال بـ 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:

دعونا ننظر في إنشاء الوظائف المتوقعة.

المساعد في الوقت الحقيقي

أولاً ، قم بإنشاء ملف 'realtime.jquery.js' داخل دليل 'src'. سيحتوي هذا الملف على وظيفة المكون الإضافي. ثم أضف ما يلي إلى الملف كنقطة بداية للمكون الإضافي:

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

يمكننا حتى اختبار ذلك الآن. في "الأمثلة / bitcoin / index.html" ، أزل المكوّن الإضافي "

إذا قمت بتحديث الصفحة الآن سترى "الوقت الحقيقي!" تسجيل الدخول إلى وحدة تحكم جافا سكريبت إلى جانب HTML من "

' جزء. هذا رائع لأنه يعني أن المكوِّن الإضافي يعمل ؛ نجحنا في تنفيذ وظيفة المكون الإضافي بنجاح على الطاولة المحددة بواسطة المحدد الذي اجتزناه إلى jQuery.

pusher_005

الإضافات jQuery ومكتبات الطرف الثالث

يعتمد المكون الإضافي للوقت الفعلي على مكتبة تابعة لجهة خارجية - مكتبة Pusher JavaScript. في الوقت الحالي ، تم تضمينه بشكل ثابت داخل HTML ، ولكننا لا نريد أن نجعل ذلك مطلبًا لاستخدام المكون الإضافي. لذا ، دعنا نحمّلها ديناميكيًا. يوفر jQuery طريقة للقيام بذلك بسهولة في شكل ".getScript ()" وظيفة.

لذا ، لنقم بتحميل الإصدار 2.0 من مكتبة Pusher JavaScript. سنقوم بتحميل الإصدار المستضاف HTTPS بحيث تكون المتصفحات سعيدة إذا تم استخدام المكون الإضافي على صفحة تم عرضها عبر HTTPS (يحظر Chrome بالفعل محاولات تحميل البرامج النصية المستضافة لـ HTTP في صفحات HTTPS وسيقوم 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 );}  )؛} function pusherLoaded (script، textStatus) {libraryLoaded = true؛ console.log ('pusher.min.js loaded:' + textStatus)؛} loadPusher ()؛ 

إذا أعدت تحميل الصفحة ، فسيتم تسجيل رسالة "pusher.min.js load: success" إلى وحدة التحكم.

بينما نعمل على التطوير ، من الجيد دائمًا أن يكون لديك طريقة لتسجيل المعلومات حتى يمكننا في هذه المرحلة إنشاء وظيفة "سجل" بسيطة يمكننا استخدامها والتي تسجل الدخول إلى وحدة التحكم. سنستخدم هذا الآن ونستخدمه أيضًا لتسجيل أحداث Pusher. المصدر الكامل للمكوِّن الإضافي هو الآن:

( 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 ('pusher.min.js loaded:' + textStatus)؛} $. fn.realtime = function () {log (' realtime! ')؛ log ($ (this) .html ())؛}؛ loadPusher ()؛} (jQuery))؛ 

ستلاحظ أيضًا أننا قمنا بتعيين وظيفة "السجل" إلى الخاصية "Pusher.log". هذا يعني أننا يمكن أن نرى تسجيل مكتبة Pusher الداخلية بالإضافة إلى منطقتنا.

متى يجب علينا الاتصال؟

نظرًا للطبيعة غير المتزامنة لتحميل المكتبة ، لا يمكننا ضمان تحميلها عند استدعاء المكون الإضافي. للأسف ، هذا يجعل الأمور أكثر تعقيدًا من المثالية ، ولكننا سنحاول حلها بطريقة بسيطة قدر الإمكان.

نحتاج إلى التحقق لمعرفة ما إذا كانت المكتبة قد حمّلت - ومن هنا علم '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 );}};

عندما يتم استدعاء المكون الإضافي ، نحدد علامة "libraryLoaded" لمعرفة ما إذا تم تحميل مكتبة Pusher JavaScript. إذا كان من الجيد أن نذهب ويمكننا الاشتراك. إذا كان لا يزال قيد الانتظار ، فسنحتاج إلى انتظار الاشتراكات. نقوم بذلك عن طريق دفع مجموعة jQuery ("els") إلى مجموعة "معلق".

الآن ، تواصل

الآن بعد أن علمنا أن مكتبة Pusher JavaScript قد تم تحميلها وأن الصفحة تريد الاشتراك في البيانات ، يمكننا إنشاء مثيل Pusher. ونظرًا لأننا لا نريد سوى مثال واحد "Pusher" لكل صفحة ، فسنتبعه نمط سينجلتون ولديك 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;}

تستولي هذه الوظيفة على علامة البرنامج النصي للمكوِّن الإضافي من خلال البحث عن علامة ذات سمة "src" تنتهي بـ "jquery.realtime.js" ، ثم تحصل على قيمة السمة "data-rt-key". ثم يقوم بإنشاء مثيل "Pusher" جديد ، يمر في المفتاح. كما ذكرنا سابقًا ، يؤدي إنشاء مثيل "Pusher" جديد إلى إنشاء اتصال بمصدر بياناتنا.

الاشتراك

يمكننا الآن استخدام وظيفة getPusher () في أي وقت نريد الوصول إلى مثيل 'Pusher'. في حالتنا نحن نريد استخدامه عندما نحلل العناصر لتحديد الاشتراكات.

قم بتحديث وظيفة "اشتراك" العنصر النائب وإضافة الوظائف الإضافية الموضحة أدناه:

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" هي وظيفة مساعدة للحصول على أي عناصر من مجموعة موجودة تتطابق مع محدد معين باستخدام '.منقي()'، جنبا إلى جنب مع أي من أحفاد العناصر باستخدام '.تجد()'. نحن نستخدم هذه الوظيفة للعثور على أي عناصر تم ترميزها لتمثيل اشتراكات القناة (سمة "بيانات rt-channel") ولكل نقطة نطلق عليها "subscribeChannel". تقوم هذه الدالة باستخراج اسم القناة المراد الاشتراك فيها واستخدامها في استدعاء "pusher.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 realtime markup find channel subscription and event binding

عرض التحديث

عندما يتم استدعاء معالج الحدث ، نحتاج إلى العثور على اسم كل خاصية على كائن "البيانات" (على سبيل المثال ، أخير ، منخفض ، مرتفع وحجم) يتم إرساله مع التحديث والعثور على أي عناصر تم وضع علامة عليها بهذا الاسم.

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

نحن ندور فوق كائن "البيانات" واحصل على اسم كل عقار. بمجرد أن نعرف اسم الخاصية ('propName') يمكننا العثور على العناصر المرتبطة وتحديث قيمتها النصية مع قيمة البيانات الجديدة. في الوقت الحالي ، لن ندعم الأشياء بأي نوع من التسلسل الهرمي - فنحن نريد فقط مستوى واحد من أزواج المفاتيح والقيم.

إذا قمت بتحديث الصفحة الآن وقمت بتشغيل حدث من Pusher Event Creator ، فسيتم عرض البيانات الجديدة على الفور داخل الصفحة.

هل عملت مع خدمة بيانات حية؟ ما هي الدروس التي تعلمتها؟ اسمحوا لنا أن نعرف في التعليقات.

صورة مميزة / صورة مصغرة ، صورة البيانات الحية عبر Shutterstock.