Ractive.js - أصبحت تطبيقات الويب سهلة
نشرت: 2022-03-11في مشهد اليوم سريع الانتشار لأطر عمل ومكتبات جافا سكريبت ، فإن اختيار الإطار الذي تريد أن تبني عليه تطورك يمكن أن يكون تحديًا كبيرًا. بعد كل شيء ، بمجرد السير في مسار استخدام إطار عمل معين ، فإن ترحيل الكود الخاص بك إلى استخدام إطار مختلف هو مهمة غير تافهة قد لا يكون لديك الوقت أو الميزانية للقيام بها.
إذن ، لماذا Ractive.js؟
بخلاف الأدوات الأخرى التي تنشئ HTML خاملًا ، يحول Ractive القوالب إلى مخططات للتطبيقات التفاعلية بشكل افتراضي. وبينما يمكن للمرء أن يجادل بالتأكيد في أن مساهمة راكتيف هي تطورية أكثر منها ثورية ، فإن قيمتها مهمة رغم ذلك.
ما يجعل Ractive مفيدًا للغاية هو أنه يوفر إمكانات قوية ، ولكنه يفعل ذلك بطريقة بسيطة منعشة للمطور لاستخدامها. علاوة على ذلك ، فهو أنيق إلى حد ما وسريع وغير مزعج وصغير.
في هذه المقالة ، سنتناول عملية إنشاء تطبيق بحث راكتيف بسيط ، مع توضيح بعض ميزات Ractive الرئيسية والطرق التي يساعد بها في تبسيط تطبيقات الويب وتطويرها.
ما هو Ractive.js؟
تم إنشاء Ractive في الأصل لمعالجة مشكلة ربط البيانات بطريقة أكثر أناقة. لتحقيق هذه الغاية ، فإنه يأخذ القوالب ويحولها إلى تمثيل افتراضي خفيف الوزن لـ DOM بحيث يتم تحديث DOM الحقيقي بذكاء وكفاءة عندما تتغير البيانات.
ولكن سرعان ما أصبح واضحًا أن النهج والبنية التحتية التي تستخدمها Ractive يمكن استخدامها للقيام بأشياء أخرى بشكل أكثر كفاءة أيضًا. يمكنه ، على سبيل المثال ، الاعتناء تلقائيًا بأشياء مثل إعادة استخدام معالجات الأحداث وإلغاء ربطها تلقائيًا عندما لا تكون هناك حاجة إليها. يصبح تفويض الحدث غير ضروري. كما هو الحال مع ربط البيانات ، يمنع هذا الأسلوب الرمز من أن يصبح غير عملي مع نمو التطبيق.
يتم توفير الميزات الرئيسية مثل الربط ثنائي الاتجاه والرسوم المتحركة ودعم SVG ، ويمكن بسهولة إضافة الوظائف المخصصة عبر المكونات الإضافية.
في حين أن بعض الأدوات والأطر تجبرك على تعلم مفردات جديدة وهيكل تطبيقك بطريقة معينة ، فإن Ractive يعمل من أجلك ، وليس العكس. كما أنه يتكامل بشكل جيد مع المكتبات الأخرى.
نموذج التطبيق لدينا
سيتم استخدام نموذج التطبيق الخاص بنا للبحث في قاعدة بيانات Toptal للمطورين بناءً على المهارات. سيحتوي تطبيقنا على وجهتي نظر:
- البحث: قائمة المهارات مع مربع البحث المضمنة
- النتائج: عرض المهارة بما في ذلك قائمة المطورين
سنعرض لكل مطور اسمه وصورته ووصف قصير وقائمة بالمهارات (كل مهارة سترتبط بعرض المهارة المقابل).
(ملاحظة: يتم توفير كل من الروابط إلى مثيل العمل عبر الإنترنت للتطبيق ومستودع كود المصدر في نهاية هذه المقالة.)
من أجل الحفاظ على تركيزنا الأساسي على إطار العمل Ractive ، سنستخدم عددًا من التبسيط الذي لا ينبغي القيام به في العادة في الإنتاج:
- النسق الافتراضي. سنستخدم Bootstrap مع السمة الافتراضية للتصميم ، بدلاً من تخصيص السمة لتلائم نمط التطبيق الخاص بك.
- التبعيات. سنضيف تبعياتنا كنصوص منفصلة تحدد المتغيرات العامة (بدلاً من استخدام وحدات ES6 أو CommonJS أو AMD مع محمل مناسب للتطوير وخطوة بناء للإنتاج).
- بيانات ثابتة. سنستخدم البيانات الثابتة التي أعددتها عن طريق كشط الصفحات العامة على موقع Toptal.
- لا يوجد توجيه من جانب العميل. هذا يعني أن عنوان URL سيبقى كما هو أثناء التبديل بين طرق العرض. بالتأكيد لا يجب عليك فعل ذلك مع SPA ، على الرغم من أنه قد يكون مناسبًا لبعض المكونات التفاعلية الصغيرة. لا يحتوي Ractive على تطبيق موجه مدمج ، ولكن يمكن استخدامه مع أجهزة توجيه تابعة لجهات خارجية ، كما هو موضح في هذا المثال.
- القوالب المعرفة داخل علامات البرنامج النصي في HTML. هذه ليست فكرة سيئة بالضرورة ، خاصة للتطبيقات الصغيرة ، ولها بعض المزايا (إنها بسيطة ، ويمكنك معالجة هذه القوالب من جانب العميل مع القوالب من جانب الخادم ، على سبيل المثال للتدويل). ولكن بالنسبة للتطبيقات الأكبر ، يمكنك الاستفادة من التجميع المسبق (المعروف أيضًا باسم قوالب التحليل المسبق لتمثيل JS الداخلي.
لنبدأ مع تطبيقات الويب
حسنًا ، مع ذلك ، لنبدأ في إنشاء التطبيق. سنقوم بذلك بطريقة تكرارية ، بإضافة ميزات أصغر واحدة تلو الأخرى واستكشاف المفاهيم كما نواجهها.
لنبدأ بإنشاء مجلد بداخله ملفان: index.html
و script.js
. سيكون تطبيقنا بسيطًا للغاية وسيعمل من file://
protocol لتجنب الحاجة إلى بدء تشغيل خادم التطوير (على الرغم من أنك تستطيع ذلك إذا كنت ترغب في ذلك).
صفحة البحث
سنبدأ بتنفيذ صفحة البحث حيث يمكن للمستخدم تحديد مهارة للعثور على مطورين مطابقين في قاعدة بيانات Toptal.
هيكل HTML
لنبدأ بصفحة HTML التافهة هذه:
<html> <head> <title>Toptal Search</title> <!-- LOAD BOOTSTRAP FROM THE CDN --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> </head> <body> <!-- SOME BASIC STATIC CONTENT --> <div class="container"> <h1>Toptal Search</h1> </div> <!-- LOAD THE JAVASCRIPT LIBRARIES WE NEED --> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.9.3/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/0.7.3/ractive.min.js"></script> <!-- LOAD THE DATA --> <script src="https://rawgit.com/emirotin/toptal-blog-ractive/master/data.js"></script> <!-- LOAD OUR SCRIPT --> <script src="script.js"></script> </body> </html>
كما ترى ، إنه مستند HTML5 تافه. يقوم بتحميل Bootstrap من CDN و Lodash (مكتبة رائعة لمعالجة البيانات) و Ractive.js.
لا يتطلب Ractive تخصيص الصفحة بأكملها لـ SPA ، لذلك يمكننا الحصول على بعض المحتوى الثابت. في حالتنا ، يتكون هذا من عنصر حاوية وعنوان الصفحة.
أخيرًا ، نقوم بتحميل البيانات التي أعددتها للعرض التوضيحي ، والبرنامج النصي الذي سيحتوي على برنامجنا.
حسنًا ، بعد أن أصبح هيكل HTML الخاص بنا في مكانه الصحيح ، فلنبدأ في إضافة بعض الوظائف الحقيقية.
قائمة المهارات
أحد الأشياء التي أحبها بشكل خاص في Ractive هو كيف يعلمك التفكير في التمثيل النهائي (HTML) الذي تريد تحقيقه ، ثم يمكّنك من التركيز على كتابة الأجزاء الضرورية من التعليمات البرمجية لتحقيق ذلك.
لذلك أولاً ، دعونا نبني قائمة بالمهارات كوجهة نظرنا الأولية. القيام بذلك يستلزم ببساطة:
- إضافة عنصر HTML حيث سيتم عرض قائمة المهارات.
- إضافة مقتطف صغير من رمز القالب إلى HTML الخاص بنا.
- كتابة بعض جافا سكريبت المختصر والبسيط الذي يوفر البيانات للقالب ، لعرضها في عنصر HTML الذي أضفناه.
تتكون تعديلات HTML مما يلي:
<div class="container"> <h1>Toptal Search</h1> <div></div> <!-- THIS IS THE NEW HTML ELEMENT --> </div> <!-- THIS IS THE SMALL SNIPPET OF TEMPLATE CODE --> <script type="text/html"> <div class="row"> {{#each skills}} <span class="col-xs-3"> <a href="#" class="label label-primary">{{this}}</a> </span> {{/each}} </div> </script>
لا توجد اتفاقية خاصة مع Ractive لتحديد عنصر HTML لتلقي البيانات المراد عرضها ، ولكن أبسط طريقة للقيام بذلك هي إضافة معرف إلى العنصر. عادةً ما أستخدم معرّف "الجذر" لهذا الغرض. سنرى قريبًا كيف يتم استخدامه عند تهيئة Ractive. بالنسبة لأولئك الفضوليين ، هناك طرق أخرى لتحديد عنصر الجذر.
عنصر البرنامج النصي المحرج نوعًا ما مع type="text/html"
هو خدعة ذكية لتحميل جزء كبير من HTML بواسطة المستعرض دون تحليله أو عرضه ، لأن المتصفحات تتجاهل البرامج النصية من نوع غير معروف. محتوى البرنامج النصي هو نموذج يشبه Moustache / Handlebars (على الرغم من أن Ractive لديها بعض الامتدادات).
نكتب أولاً رمز القالب بافتراض أن لدينا إمكانية الوصول إلى مجموعة المهارات. نستخدم {{#each}}
التوجيه الشارب لتعريف التكرار. داخل التوجيه ، يمكن الوصول إلى العنصر الحالي على this
النحو. مرة أخرى ، نفترض أن متغير المهارات يحتوي على مصفوفة من السلاسل ، لذا فإننا نعرضها ببساطة باستخدام شارب الاستيفاء {{this}}
.
حسنًا ، هذا هو HTML. لكن ماذا عن JavaScript؟ هذا هو المكان الذي يحدث فيه "السحر" الذي يوفر البيانات للقالب:
(function () { var skills = DB.skills, developers = DB.developers; var app = new Ractive({ el: '#root', template: '#tpl-app', data: { skills: _.keys(DB.skills) } }); }());
مثير للإعجاب ، أليس كذلك؟ في هذه الأسطر العشرة من الكود يمكننا:
- "استرداد" البيانات من "DB".
- إنشاء تطبيق Ractive جديد.
- اطلب منه عرض داخل العنصر بامتداد
.
- اطلب منه استخدام عنصر نصي مع
للحصول على النموذج (هناك طرق أخرى للقيام بذلك أيضًا).
- قم بتمرير البيانات الأولية (سنرى كيفية تغييرها في وقت التشغيل) ، أو "النطاق" إذا كنت معتادًا على المصطلحات الزاويّة.
- استخدم طريقة Lodash
keys
للحصول على أسماء المهارات التي نستخدمها كمفاتيح كائنات في "DB".
لذلك ، باستخدام هذا البرنامج النصي ، نخبر إطار العمل بما يجب القيام به ، ولكن ليس كيفية القيام بذلك. يوضح النموذج كيف أجده ، وأنا شخصيًا ، مذهلًا وطبيعيًا.
نأمل أن تكون قد بدأت في الحصول على الفكرة ، لذلك دعونا الآن ننفذ شيئًا أكثر فائدة بالإضافة إلى ما لدينا.
البحث عن المهارات
تحتاج صفحة البحث بالطبع إلى حقل بحث. ونود أن يوفر إمكانية تفاعلية حيث يتم تصفية قائمة المهارات ، كما يكتب المستخدم في مربع البحث ، فقط تلك التي تحتوي على السلسلة الفرعية التي تم إدخالها (مع كون التصفية غير حساسة لحالة الأحرف).
كالعادة مع Ractive ، نبدأ بتحديد القالب (مع التفكير في متغيرات السياق الجديدة التي ستكون مطلوبة ، وما الذي سيتغير فيما يتعلق بإدارة البيانات):
<div class="container"> <h1>Toptal Search</h1> <div></div> </div> <!-- THIS IS THE SMALL SNIPPET OF TEMPLATE CODE --> <script type="text/html"> <!-- HERE'S OUR SEARCH BOX --> <div class="row"> <form class="form-horizontal col-xs-6 col-xs-offset-6"> <input type="search" class="form-control" value="{{ skillFilter }}" placeholder="Type part of the skill name here"> </form> </div> <hr> <!-- NOW INSTEAD OF DISPLAYING ALL SKILLS, WE INVOKE A TO-BE-CREATED JAVASCRIPT skills() FUNCTION THAT WILL FILTER THE SKILL LIST DOWN TO THOSE THAT MATCH THE TEXT ENTERED BY THE USER --> <div class="row"> {{#each skills()}} <span class="col-xs-3"> <a href="#" class="label label-primary">{{this}}</a> </span> {{/each}} </div> </script>
ليس هناك الكثير من التغييرات ، ولكن لا يزال هناك قدر لا بأس به لنتعلمه.
أولاً ، أضفنا <div> جديدًا يحتوي على مربع البحث الخاص بنا. من الواضح أننا نريد ربط هذا الإدخال ببعض المتغيرات (إلا إذا كنت تشعر بالحنين إلى أيام حساء jQuery القديمة الجيدة). يدعم Ractive ما يسمى بالربط ثنائي الاتجاه ، مما يعني أن كود JS الخاص بك يمكنه استرداد قيمة دون الحاجة إلى قراءتها يدويًا من DOM. في حالتنا ، يتم تحقيق ذلك باستخدام value="{{ skillFilter }}"
. يتفهم راكتيف أننا نريد ربط هذا المتغير بسمة قيمة المدخلات. لذلك فهو يراقب المدخلات لنا ويقوم تلقائيًا بتحديث المتغير. أنيق جدًا بسطر واحد فقط من HTML.
ثانيًا ، كما هو موضح في التعليق في مقتطف الشفرة أعلاه ، الآن بدلاً من عرض جميع المهارات ، سننشئ وظيفة skills()
JS التي ستعمل على تصفية قائمة المهارات وإرجاع فقط تلك التي تطابق النص الذي أدخله المستخدم:
// store skill list in a variable outside of Ractive scope var skillNames = _.keys(DB.skills); var app = new Ractive({ el: '#root', template: '#tpl-app', data: { // initializing the context variable is not strictly // required, but it is generally considered good practice skillFilter: null, // Define the skills() function right in our data object. // Function is available to our template where we call it. skills: function() { // Get the skillFilter variable from the Ractive instance // (available as 'this'). // NOTE WELL: Our use of a getter here tells Ractive that // our function has a *dependency* on the skillFilter // value, so this is significant. var skillFilter = this.get('skillFilter'); if (!skillFilter) { return skillNames; } skillFilter = new RegExp(_.escapeRegExp(skillFilter), 'i') return _.filter(skillNames, function(skill) { return skill.match(skillFilter); }); } } });
في حين أن هذا نظيف وسهل التنفيذ ، فقد تتساءل عن كيفية تأثيره على الأداء. أعني ، سنقوم باستدعاء دالة في كل مرة؟ حسنا ، في كل مرة ماذا؟ يعتبر Ractive ذكيًا بما يكفي لإعادة عرض أجزاء من القالب فقط (واستدعاء أي وظائف منها) عندما تتغير تبعياتها (المتغيرات) (يعرف Ractive متى يحدث ذلك بفضل استخدام المحددات).

بالمناسبة ، لأولئك المهتمين بأخذ هذه الخطوة إلى الأمام ، هناك أيضًا طريقة أكثر أناقة للقيام بذلك باستخدام خاصية محسوبة ، لكنني سأترك ذلك لك لتلعب به بمفردك إذا أردت.
صفحة النتائج
الآن بعد أن أصبح لدينا قائمة مهارات قابلة للبحث ، دعنا ننتقل إلى عرض النتائج حيث سيتم عرض قائمة المطورين المطابقة.
التبديل من وإلى عرض المهارة
من الواضح أن هناك طرقًا متعددة يمكن من خلالها تنفيذ ذلك. لقد اخترت نهج وجود وجهتي نظر مختلفتين اعتمادًا على ما إذا تم اختيار المهارة أم لا. إذا كان الأمر كذلك ، فإننا نعرض قائمة المطورين المطابقين ؛ إذا لم يكن كذلك ، فإننا نعرض قائمة المهارات ومربع البحث.
لذلك ، بالنسبة للمبتدئين ، عندما يختار المستخدم (على سبيل المثال ، النقر فوق) اسم مهارة ، يجب إخفاء قائمة المهارات ويجب إظهار اسم المهارة بدلاً من ذلك كعنوان للصفحة. على العكس من ذلك ، في طريقة عرض المهارة المحددة ، يجب أن تكون هناك طريقة لإغلاق هذا العرض والعودة إلى قائمة المهارات.
هذه هي خطوتنا الأولى في هذا المسار:
<script type="text/html"> <!-- PARTIAL IS A NEW CONCEPT HERE --> {{#partial skillsList}} <div class="row"> <form class="form-horizontal col-xs-6 col-xs-offset-6"> <input type="search" class="form-control" value="{{ skillFilter }}" placeholder="Type part of the skill name here"> </form> </div> <hr> <div class="row"> {{#each skills()}} <span class="col-xs-3"> <!-- MAKE OUR SKILLS CLICKABLE, USING PROXY EVENTS --> <a href="#" class="label label-primary" on-click="select-skill:{{this}}">{{this}}</a> </span> {{/each}} </div> {{/partial}} {{#partial skillView}} <h2> <!-- DISPLAY SELECTED SKILL AS HEADING ON THE PAGE --> {{ currentSkill }} <!-- CLOSE BUTTON TAKES USER BACK TO SKILLS LIST --> <button type="button" class="close pull-right" on-click="deselect-skill">× CLOSE</button> </h2> {{/partial}} <!-- PARTIALS ARE NOT IN THE VIEW UNTIL WE EXPLICITLY INCLUDE THEM, SO INCLUDE THE PARTIAL RELEVANT TO THE CURRENT VIEW. --> {{#if currentSkill}} {{> skillView}} {{else}} {{> skillsList}} {{/if}} </script>
حسنًا ، هناك الكثير مما يحدث هنا.
أولاً ، لاستيعاب تنفيذ هذا كوجهتي نظر مختلفتين ، قمت بنقل كل شيء لدينا حتى الآن (أي عرض القائمة) إلى شيء يسمى جزئي. الجزء الجزئي عبارة عن جزء كبير من رمز القالب الذي سنقوم بتضمينه في مكان مختلف (قريبًا).
بعد ذلك ، نريد أن نجعل مهاراتنا قابلة للنقر ، وعندما يتم النقر عليها نريد الانتقال إلى عرض المهارة المقابل. لهذا ، نستخدم شيئًا يسمى أحداث الوكيل ، حيث نتفاعل مع حدث مادي (عند النقر ، الاسم هو الذي يفهمه Ractive) ونقوم بتوكيله إلى الحدث المنطقي (حدد مهارة ، الاسم هو كل ما نسميه ) اجتياز المناقشة (كما تتذكر على الأرجح أن هذا يشير إلى اسم المهارة هنا).
(لمعلوماتك ، توجد صيغة بديلة لاستدعاءات الطريقة لتحقيق نفس الشيء.)
بعد ذلك ، نفترض (مرة أخرى) أنه سيكون لدينا متغير يسمى currentSkill
والذي سيكون له اسم المهارة المحددة (إن وجدت) ، أو سيكون فارغًا إذا لم يتم تحديد أي مهارات. لذلك قمنا بتعريف جزء آخر يُظهر اسم المهارة الحالية ، وله أيضًا رابط "إغلاق" الذي يجب أن يلغي تحديد المهارة.
بالنسبة إلى JavaScript ، تتمثل الإضافة الرئيسية في الكود الخاص بالاشتراك في أحداث المهارة المحددة وإلغاء تحديد المهارة ، وتحديث currentSkill
الحالية ( skillFilter
) وفقًا لذلك:
var app = new Ractive({ el: '#root', template: '#tpl-app', data: { skillFilter: null, currentSkill: null, // INITIALIZE currentSkill TO null // skills function remains unchanged skills: function() { var skillFilter = this.get('skillFilter'); if (!skillFilter) { return skillNames; } skillFilter = new RegExp(_.escapeRegExp(skillFilter), 'i') return _.filter(skillNames, function(skill) { return skill.match(skillFilter); }); } } }); // SUBSCRIBE TO LOGICAL EVENT select-skill app.on('select-skill', function(event, skill) { this.set({ // SET currentSkill TO THE SKILL SELECTED BY THE USER currentSkill: skill, // RESET THE SEARCH FILTER skillFilter: null }); }); // SUBSCRIBE TO LOGICAL EVENT deselect-skill app.on('deselect-skill', function(event) { this.set('currentSkill', null); // CLEAR currentSkill });
قائمة المطورين لكل مهارة
بعد إعداد العرض الجديد للمهارة ، يمكننا الآن إضافة بعض العناصر - القائمة الفعلية للمطورين لدينا لتلك القائمة. لذلك نقوم بتوسيع الجزئية لهذا العرض على النحو التالي:
{{#partial skillView}} <h2> {{ currentSkill }} <button type="button" class="close pull-right" on-click="deselect-skill">× CLOSE</button> </h2> {{#each skillDevelopers(currentSkill)}} <div class="panel panel-default"> <div class="panel-body"> {{ this.name }} </div> </div> {{/each}} {{/partial}}
نأمل في هذه المرحلة أن تشعر بما يحدث هنا: لقد أضفنا قسمًا جديدًا للتكرار إلى skillView
جزئي يكرر نتيجة وظيفة جديدة skillDevelopers
بعد ذلك. لكل مطور في المصفوفة (يتم إرجاعه بواسطة وظيفة skillDevelopers
) ، نقوم بعرض لوحة وعرض اسم المطور. لاحظ أنه يمكنني استخدام النموذج الضمني {{name}}
هنا وسيجد Ractive السمة المناسبة من خلال البحث في سلسلة السياق بدءًا من السياق الحالي (وهو في حالتنا كائن المطور المرتبط بـ {{#each}}
) ، ولكن أفضل أن أكون صريحًا. يتوفر مزيد من المعلومات حول السياقات والمراجع في وثائق Ractive.
وها هو تنفيذ skillDevelopers()
:
skillDevelopers: function(skill) { // GET THE SKILL OBJECT FROM THE “DB” skill = skills[skill]; // SAFETY CHECK, RETURN EARLY IN CASE OF UNKNOWN SKILL NAME if (!skill) { return; } // MAP THE DEVELOPER'S IDs (SLUGS) TO THE // ACTUAL DEVELOPER DETAIL OBJECTS return _.map(skill.developers, function(slug) { return developers[slug]; }); }
توسيع الدخول لكل مطور
الآن بعد أن أصبح لدينا قائمة عمل بالمطورين ، حان الوقت لإضافة المزيد من التفاصيل ، وصورة جميلة بالطبع:
{{#partial skillView}} <h2> {{ currentSkill }} <button type="button" class="close pull-right" on-click="deselect-skill">× CLOSE</button> </h2> {{#each skillDevelopers(currentSkill)}} <div class="panel panel-default"> <div class="panel-body media"> <div class="media-left"> <!-- ADD THE PHOTO --> <img class="media-object img-circle" width="64" height="64" src="{{ this.photo }}" alt="{{ this.name }}"> </div> <div class="media-body"> <!-- MAKE THE DEVELOPER'S NAME A HYPERLINK TO THEIR PROFILE --> <a class="h4 media-heading" href="{{ this.url }}" target="_blank"> {{ this.name }}</a> <!-- ADD MORE DETAILS (FROM THEIR PROFILE) --> <p>{{ this.desc }}</p> </div> </div> </div> {{/each}} {{/partial}}
لا شيء جديد هنا من الجانب التفاعلي للأشياء ، ولكن استخدامًا أثقل قليلاً لميزات Bootstrap.
عرض قائمة قابلة للنقر من مهارات المطور
لقد أحرزنا تقدمًا جيدًا حتى الآن ، ولكن هناك ميزة واحدة لا تزال مفقودة وهي الجانب الآخر من علاقة مطور المهارات ؛ على وجه التحديد ، نريد عرض مهارات كل مطور ونريد أن تكون كل من هذه المهارات رابطًا قابلًا للنقر يأخذنا إلى عرض النتائج لهذه المهارة.
لكن انتظر ... أنا متأكد من أن لدينا بالفعل نفس الشيء بالضبط في قائمة المهارات. نعم ، في الواقع ، نحن نفعل ذلك. إنه مدرج في قائمة المهارات القابلة للنقر ، ولكن هذا يأتي من مجموعة مختلفة من مجموعة مهارات كل مطور. ومع ذلك ، فإن هذه متشابهة بدرجة كافية لدرجة أنها علامة واضحة بالنسبة لي على أنه يجب علينا إعادة استخدام هذا الجزء من HTML. ولتحقيق هذه الغاية ، فإن الجزئيات هي صديقنا.
(ملاحظة: لدى Ractive أيضًا نهجًا أكثر تقدمًا للقطع القابلة لإعادة الاستخدام من العرض ، والمعروفة باسم المكونات. إنها مفيدة حقًا ، ولكن من أجل البساطة ، لن نناقشها الآن.)
إذن ، إليك كيفية تحقيق ذلك باستخدام الأجزاء (ولاحظ ، بالمناسبة ، أننا قادرون على إضافة هذه الوظيفة دون إضافة سطر واحد من كود JavaScript!):
<!-- MAKE THE CLICKABLE SKILL LINK INTO ITS OWN “skill” PARTIAL --> {{#partial skill}} <a href="#" class="label label-primary" on-click="select-skill:{{this}}">{{this}}</a> {{/partial}} {{#partial skillsList}} <div class="row"> <form class="form-horizontal col-xs-6 col-xs-offset-6"> <input type="search" class="form-control" value="{{ skillFilter }}" placeholder="Type part of the skill name here"> </form> </div> <hr> <div class="row"> {{#each skills()}} <!-- USE THE NEW “skill” PARTIAL --> <span class="col-xs-3">{{> skill}}</span> {{/each}} </div> {{/partial}} {{#partial skillView}} <h2> {{ currentSkill }} <button type="button" class="close pull-right" on-click="deselect-skill">× CLOSE</button> </h2> {{#each skillDevelopers(currentSkill)}} <div class="panel panel-default"> <div class="panel-body media"> <div class="media-left"> <img class="media-object img-circle" width="64" height="64" src="{{ this.photo }}" alt="{{ this.name }}"> </div> <div class="media-body"> <a class="h4 media-heading" href="{{ this.url }}" target="_blank">{{ this.name }}</a> <p>{{ this.desc }}</p> <p> <!-- ITERATE OVER THE DEVELOPER'S SKILLS --> {{#each this.skills}} <!-- REUSE THE NEW “skill” PARTIAL TO DISPLAY EACH DEVELOPER SKILL AS A CLICKABLE LINK --> {{> skill}} {{/each}} </p> </div> </div> </div> {{/each}} {{/partial}}
لدي بالفعل قائمة المهارات المرفقة بكائن المطور الذي استرجعناه من "DB" ، لذلك قمت بتغيير القالب قليلاً: لقد قمت بنقل السطر الذي يجعل تسمية المهارة جزئية واستخدمت هذا الجزء حيث كان هذا السطر في الأصل.
بعد ذلك ، عندما أقوم بتكرار مهارات المطور ، يمكنني إعادة استخدام هذا الجزء الجديد نفسه لعرض كل من هذه المهارات كارتباط قابل للنقر أيضًا. علاوة على ذلك ، يؤدي هذا أيضًا إلى تمثيل حدث تحديد المهارة ، إذا كنت تتذكر ، تمرير نفس اسم المهارة. هذا يعني أنه يمكننا تضمين هذا في أي مكان (مع وجود السياق المناسب) وسوف نحصل على تسمية قابلة للنقر تؤدي إلى عرض المهارة!
اللمسة النهائية - أداة التحميل المسبق
حسنًا ، لدينا الآن تطبيق وظيفي أساسي. إنه نظيف ويعمل بسرعة ، لكنه لا يزال يستغرق بعض الوقت للتحميل. (في حالتنا ، يرجع هذا جزئيًا إلى استخدامنا لمصادر غير متسلسلة وغير مصغرة ، ولكن في تطبيق العالم الحقيقي يمكن أن تكون هناك أسباب مهمة أخرى ، مثل تحميل البيانات الأولية).
لذا ، كخطوة أخيرة ، سأعرض لك خدعة أنيقة لإضافة رسم متحرك مسبق التحميل ستتم إزالته بمجرد أن يعرض Ractive تطبيقنا:
<div class="container"> <h1>Toptal Search</h1> <div> <div class="progress"> <div class="progress-bar progress-bar-striped active"> Loading... </div> </div> </div> </div>
إذن ما هو السحر هنا؟ إنه في الواقع بسيط للغاية. لقد أضفت بعض المحتوى (إنه شريط تقدم متحرك لـ Bootstrap ، ولكن يمكن أن يكون صورة GIF متحركة ، أو أي شيء آخر) مباشرة إلى عنصر الجذر الخاص بنا. أعتقد أنه ذكي جدًا - أثناء تحميل البرامج النصية الخاصة بنا ، يرى المستخدم مؤشر التحميل (نظرًا لعدم اعتماده على JavaScript ، يمكن عرضه على الفور). ومع ذلك ، بمجرد تهيئة التطبيق Ractive ، سيقوم Ractive بالكتابة فوق محتوى عنصر الجذر (وبالتالي محو الرسوم المتحركة التي تم تحميلها مسبقًا) بالقالب المعروض. بهذه الطريقة ، نحن قادرون على تحقيق هذا التأثير مجرد جزء من HTML ثابت و 0 سطر من المنطق. أعتقد أن هذا رائع جدًا.
خاتمة
فكر في ما أنجزناه هنا وكيف أنجزناه بسهولة. لدينا تطبيق شامل جدًا: فهو يعرض قائمة بالمهارات ، ويسمح بالبحث خلالها بسرعة (بل ويدعم التحديث التفاعلي لقائمة المهارات كما يكتب المستخدم في مربع البحث) ، ويسمح بالانتقال إلى مهارة معينة والعودة ، والقوائم المطورين لكل مهارة مختارة. علاوة على ذلك ، يمكننا النقر فوق أي مهارة مدرجة من قبل أي مطور لنقلنا إلى قائمة المطورين بهذه المهارة. وكل ذلك بأقل من 80 سطرًا من HTML وأقل من 40 سطرًا من JavaScript. في رأيي ، هذا مثير للإعجاب للغاية ويتحدث كثيرًا عن قوة وأناقة وبساطة Ractive.
نسخة العمل من التطبيق متاحة على الإنترنت هنا وشفرة المصدر الكاملة عامة ومتاحة هنا.
بالطبع ، بالكاد خدشنا السطح في هذه المقالة لما هو ممكن مع إطار عمل Ractive. إذا كنت تحب ما رأيته حتى الآن ، فأنا أشجعك بشدة على البدء في إعداد Ractive لمدة 60 ثانية والبدء في استكشاف كل ما تقدمه Ractive بنفسك.