اذهب إلى المحتوى

أصبحت تطبيقات الويب ذات الصفحة الوحيدة Single Page Apps رائجةً في هذه الفترة في تطوير الويب، فأمسى كل شخصٍ يريد أن ينُشِئ تطبيق ويب ذا صفحةٍ وحيدة.
سأريك في هذا الدرس طريقةٍ سهلة لإنشاء تطبيقات الويب ذات الصفحة الوحيدة باستخدام jQuery ودون استخدام أيّة إطارات عمل مثل React أو Angular أو Vue …إلخ.

jqeury-spa.png

لمحة

لأننا نريد إنشاء تطبيق ويب ذا صفحةٍ وحيدة، فسنستخدم sammy.js للتوجيه (routing)، مكتبة Sammy هي مكتبة jQuery بمساحة تخزينية لا تتجاوز 5.2 كيلوبايت.
سيبدو سكربت التوجيه المكتوب لإضافة Sammy كما يلي:

var app = $.sammy(function() {

  this.get('#/', function() {
    //your function
  });
  this.get('#about/', function() {
    //your function 
  });
  this.get('#contact/', function() {
    //your function
  });
});

علينا أولًا تهيئة التطبيق باستخدام ‎$.sammy وتخزين نسخة من الكائن في المتغير app. يمكننا تعريف تعليمة «توجيه» (route) في sammy بالطريقة الآتية:

this.get('path/',function(){
// ...
}); 

هنالك دالة ستُستدعى لكل عملية توجيه، والتي يمكن أن نكتب بداخلها البنية المنطقية لها، ونربط البيانات اللازمة إلى كل «صفحة»، لأن كل عملية توجيه ستؤدي إلى إظهار «صفحة» مختلفة.
بعد تعريف كل تعليمات التوجيه، فسنتمكن من تشغيل تطبيق الويب ذي الصفحة الوحيدة باستدعاء الدالة run()‎ التابعة للكائن app كالتالي app.run()‎.

تطبيق التدوين الذي سننشئه

لتوضيح المفهوم الذي سنشرحه، فسنحاول إنشاء مثال واقعي. لنفترض أننا نريد إنشاء مدونة بسيطة، التي يوجد فيها صفحة رئيسية (أي صفحة Home) وصفحة معلومات (About). سنُنشِئ في صفحة index قائمة بالتدوينات، والضغط على أي واحدة منها سيأخذنا إلى صفحتها. يمكنك أن تجرب هذا التطبيق عمليًا هنا.
سنستخدم صيغة JSON لقائمة التدوينات، وسنستخدم إضافة Sammy لعرضها.

بنية الملفات

- index.html <!-- main layout -->
- app.js <!-- stores all our routing logic -->
- css
--- style.css 
- js
--- jquery-1.11.3.min.js
--- sammy.min.js
--- sammy.template.js 
- data
--- articles.json
- templates <!-- the templates pages that will be injected into the main layout -->
--- article.template
--- article-detail.template
--- about.template

شيفرة HTML

سنستخدم قالب HTML boilerplate لإنشاء شيفرة HTML:

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script  src="js/jquery-1.11.3.min.js" type="text/javascript"></script>
  <script  src="js/sammy.min.js" type="text/javascript"></script>
  <script src="js/sammy.template.js" type="text/javascript"></script>
  <link rel="stylesheet" href="css/style.css" />
  <script src="app.js"></script>
</head>

<body>
  <div class="header-container">
    <header class="wrapper clearfix">
      <nav>
        <ul>
          <li><a href="#/">Home</a></li>
          <li><a href="#/about/">About</a></li> <!-- defining nav url according to route-->
        </ul>
      </nav>
    </header>
  </div>

  <div class="main-container">
    <div class="main wrapper clearfix">
      <div id="app">
      <!-- template will be injected here -->
      </div>
    </div>
  </div>
</body>
</html>

تعريف التوجيهات

//app.js
(function($) {

  var app = $.sammy('#app', function() {
    this.use('Template');

    this.around(function(callback) {
      var context = this;
      this.load('data/articles.json')
          .then(function(items) {
            context.items = items;
          })
          .then(callback);
    });

    this.get('#/', function(context) {
      context.app.swap('');
      $.each(this.items, function(i, item) {
        context.render('templates/article.template', {id: i, item: item})
               .appendTo(context.$element());
      });
    });

    this.get('#/about/', function(context) {
        var str=location.href.toLowerCase();
        context.app.swap('');
        context.render('templates/about.template', {})
               .appendTo(context.$element());
    });

    this.get('#/article/:id', function(context) {
      this.item = this.items[this.params['id']];
      if (!this.item) { return this.notFound(); }
      this.partial('templates/article-detail.template');
    });


    this.before('.*', function() {

        var hash = document.location.hash;
        $("nav").find("a").removeClass("current");
        $("nav").find("a[href='"+hash+"']").addClass("current");
   });

  });

  $(function() {
    app.run('#/about/');
  });

})(jQuery);

هيئنا في البداية التطبيق داخل العنصر ‎#app، حيث سنُضيف القوالب المختلفة بناءً على مسار التوجيه. سنستخدم أيضًا محرك قوالب باسم sammy template engine.

this.use('Template');

سنحصل على بيانات المدونة من ملف articles.json باستخدام الدالة load()‎ التابعة لمكتبة jQuery (يمكنك أيضًا استخدام ‎$.get أو ‎$.post)، وتخزين الناتج في المتغير context.
حان الآن الوقت لتعريف تعليمة التوجيه لصفحة index باستخدام ‎#/‎:

this.get('#/', function(context) {
  context.app.swap('');
  $.each(this.items, function(i, item) {
    context.render('templates/article.template', {id: i, item: item})
           .appendTo(context.$element());
  });
});

لدينا بيانات مخزنة في المتغير context، سنمرّ الآن عبر تلك البيانات عبر حلقة تكرار باستعمال الدالة ‎$.each ثم عرضها في article.template. سنستخدم أيضًا الدالة context.app.swap()‎ لكي نُفرِّغ العنصر الذي سنضع فيه المحتويات (أي ‎#app) مما فيه قبل عرض القالب.

<article>
  <section>
    <a href="#/article/<%= id %>"><h2><%= item.title %></h2></a>
  </section>
</article>

سنستخدم هنا مُحرِّك القوالب (templating engine) لكي نعرض القيم القابلة للتغيير باستخدام الصيغة ‎<%= yourdata %>‎، يمكنك أيضًا إضافة رابط لصفحة تفاصيل كل مقالة باستخدام الصيغة ‎#/article/<%= id %>‎.
الضغط على رابط التدوينة سيأخذنا إلى قالب article-detail.template، حيث نستطيع إظهار صورة التدوينة وملخص عنها …إلخ.
وخلف الكواليس، سنُعرِّف تعليمة توجيه إلى تفاصيل التدوينة في ملف app.js، وسنحصل على مُعرِّف التدوينة كمعامل (parameter) ثم نُمرِّر البيانات إلى article-detail.template.

this.get('#/article/:id', function(context) {
  this.item = this.items[this.params['id']];
  if (!this.item) { return this.notFound(); }
  this.partial('templates/article-detail.template');
});

وبشكلٍ شبيه، يمكننا إنشاء صفحة ثابتة باسم «about» ونعرضها عبر قالب about.template.

this.get('#/about/', function(context) {
    var str=location.href.toLowerCase();
    context.app.swap('');
    context.render('templates/about.template', {})
           .appendTo(context.$element());
});

لقد نسينا أهم خطوة، ألا وهي تهيئة التطبيق باستخدام app.run()‎ حيث يمكنك تحديد مكان التوجيه الافتراضي لتطبيقك. إذا أردتَ أن تفتح صفحة about أولًا فيمكنك أن تكتب:

$(function() {
  app.run('#/about/');
});

إذا أردتَ إجراء بعض العمليات قبل استدعاء كل تعليمة توجيه، فيمكنك استخدام الدالة before()‎. سنُجري في الأسطر الآتية تعديلاتٍ على قائمة التنقل (nav) اعتمادًا على مسار التوجيه الحالي:

this.before('.*', function() {
     var hash = document.location.hash;
     $("nav").find("a").removeClass("current");
     $("nav").find("a[href='"+hash+"']").addClass("current");
});

الخلاصة

هذا درسٌ بسيطٌ جدًا لكي تأخذ فكرة عن كيفية عمل تطبيق ذي صفحةٍ وحيدةٍ باستخدام jQuery. يمكنك الآن المضي قدمًا وإنشاء تطبيقات ذات صفحة وحيدة. إحدى الأشياء التي عليك أن تأخذها بعين الاعتبار هي أنَّك ستحتاج إلى خادوم ويب لتشغيل التطبيق، ويمكنك أيضًا تجربة متصفح Firefox، لأنَّ متصفح Chrome يحجب طلبيات Ajax لأيّة بروتوكولات ما عدا http://‎ أو https://‎، لذا إذا كنتَ ستُشغِّل هذا السكربت على جهازك المحلي فلن يعمل لأنَّ مسارات الملفات المحلية تبدأ بالسابقة file://‎.
ترجمة –وبتصرّف– للمقال Single Page Apps with jQuery Routing لصاحبه Arkaprava Majumder

تم التعديل في بواسطة يوغرطة بن علي


تفاعل الأعضاء

أفضل التعليقات



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...