SPA -Single Page App with jQuery Routing

Lượt xem: 12885

Xem demo

SPA - Single Page App with jQuery Routing

Sinlge Page App hay ứng dụng trang đơn đang là một thị trường màu mỡ của ngành phát triển web. Mọi người đều muốn xây dựng một SPA hay một trang đơn. Trong bài viết này chúng ta thực hiện xây dựng một SPA đơn giản nhanh chóng mà không sử dụng bất kỳ khuôn khổ MVC nào như Angular, Vue, React...

Tổng quan

 Khi chúng ta đang xây dựng một SPA thì chúng ta không muốn làm mới bất kỳ trang nào, chúng ta sẽ sử dụng sammy.js để định tuyến (routing). Sammy là thư viện jQuery chỉ có 5,2K. Chúng ta xác định routing với Sammy với cú pháp như sau: (Tải sammy.js ở link http://sammyjs.org/download#packages)


var app = $.sammy(function() {
 
  this.get('#/', function() {
    //your function
  });
  this.get('#about/', function() {
    //your function 
  });
  this.get('#contact/', function() {
    //your function
  });
});
app.run();
  

Trước tiên chúng ta cần khởi tạo ứng dụng bằng cách sử dụng  $.sammy và lưu trữ thực thể vào ứng dụng. Trong Sammy chúng ta xác định một định tuyến (routing) bằng cú pháp:


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

Trong mỗi route sẽ có một hàm callback nơi chúng ta có thể viết logic của mình, liên kết dữ liệu cụ thể cho từng view/page/screen, vì mỗi route đại diện cho một view.

Sau khi xác định toàn bộ routes chúng ta có thể bootstrap SPA bằng lệnh app.run();

Blog App của chúng ta

Để làm rõ khái niệm này, chúng ta hay cùng tìm hiểu một ví dụ thực tế. Chúng ta chỉ cần tạo một blog đơn giản. Trong đó các trang chính (ví dụ: Trang chủ) và trang giới thiệu. Trong trang chủ hoặc trang chỉ mục, chúng ta sẽ có một danh sách các bài viết, khi nhấn vào tưng mục sẽ đưa chúng ta đến trang chi tiết.

Chúng ta sẽ sử dụng danh sách bài viết dữ liệu JSON tĩnh và chúng ta sử dụng plugin tạo template của Sammy để phân tách từng view.

Cấu trúc file


- index.html  <!-- main layout --> 
- app.js  <!-- lưu trữ tất cả các routes --> 
- css
--- style.css 
- js
--- jquery-1.11.3.min.js
--- sammy.min.js
--- sammy.template.js
- data
--- articles.json
- templates  <!-- trang template sẽ được nạp vào main layout--> 
--- article.template
--- article-detail.template
--- about.template

Cấu trúc 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> <!-- xác định url điều hướng-->
        </ul>
      </nav>
    </header>
  </div>
 
 <div class="main-container">
    <div class="main wrapper clearfix">
     <div id="app">
      <!-- template sẽ được nạp vào đây -->
      </div>
   </div>
  </div>
</body>
</html>

Xác định Routes


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

Trước tiên, chúng ta cần khởi tạo ứng dụng trong thẻ div "#app", nơi chúng ta sẽ nạp các template từ đường dẫn định tuyến (route path). Như đề cập chúng ta sẽ sử dụng Sammy template engine.


this.use('Template');
  

chúng ta tìm nạp dữ liệu blog từ articles.json sử dụng Jquery load (bạn cũng có thể sử dụng $.get or $.post) phương thức được lưu trữ vào biến bối cảnh.

Bây giờ xác định route hoặc trang index sử dụng "#/"


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

Chúng ta đã thực sự có dữ liệu trong ngữ cảnh (context), chúng ta sẽ lặp qua tất cả dữ liệu và kết xuất (rendering) nó trong article.template. Chúng ta cũng sử dụng context.app.swap(''); phương thức chỉ cần xoá vùng nội dung (ví dụ trong #app) trước khi kết xuất template.


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

Vì chúng ta sử dụng templating engine để chúng ta có thể tạo giá trị động sử dụng <%= yourdata %> . Bạn có thể thấy chúng ta đẫ liên kết trang bài viết chi tiết cho mỗi bài viết sử dụng #/article/<%=id%>

Phía sau bối cảnh (behid the scene), chúng ta cũng xác định một route cho trang chi tiết  trong app.js. Chúng ta láy chỉ mục dưới dạng tham số URL và chuyển dữ liệu tới 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');
});
  

Tương tự, chúng ta cũng đã tạo một trang tĩnh gọi là "about" và kết xuất vào about.template


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

Làm xong, rất tiếng, chúng ta quên bootstrap ứng dụng của chúng ta bằng app.run() nơi bạn có thể đề cập đến route mặc định. Nếu bạn muốn mở trang about trước bạn cần xác định định app.run('#/about')


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

nếu bạn muốn thực hiện một số thao tác trước khi gọi từng route, bạn có thể sử dụng trước phương thức. ở đây chúng ta đang chọn menu điều hướng hiện tại theo đường dẫn hiện tại.


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

Vì vậy, đây là bài viết rất cơ bản về việc bắt đầu với jquery routing. Bây giờ bạn có thể tiếp tục tạo các trang đơn lớn hơn. Một điều cần nhớ routing cần một web server để chạy, hoặc bạn có thể sử dụng một server PHP hoặc Node server. Bạn cũng có thể thử với Firefox. Chrome đã chặn AJAX với bất kỳ giao thức nào khác ngoài http:// hoặc https:// vì vậy nếu bạn chạy mã này trên local ứng dụng sẽ không chạy vì liên kết bắt đầu bằng file://

 

Sản phẩm hoàn chỉnh

Tải source tại đây

Tham khảo thêm https://coderexample.com/single-page-apps-jquery-routing/

Xem demo