Tạo một "Pure router JS" cho một Single Page Application
Single Page Application (SPA) đang là một xu hướng rất phát triển trong lập trình web hiên nay. Là một web developer, chắc hẳn chúng ta đều không quá xa lạ với khái niệm này. Với sự phát triển ngày càng mạnh của các library, framework, cụ thể là 3 cái tên nổi bật nhất là: ReactJS, VueJS và Angular, đã hỗ trợ việc tạo ra các SPA một cách nhanh chóng, hiệu quả hơn. Rõ ràng không thể phủ định được độ tiện dụng cũng như độ dễ hiểu, dễ sử dụng của các library, framework kia mang lại. Tuy nhiên, chính vì chúng quá dễ sử dụng khiến cho các newbie frontend dev hay bị phụ thuộc vào chúng quá nhiều và không hiểu được cách các library, framework đó hoạt động như thế nào. Vì thế, ở bài viết dưới đây, chúng ta hãy cùng nhau đi tìm hiểu cách tạo một Router (xương sống của một SPA) bằng Javascript thuần.
Các bước tạo ra một Router cho SPA
1: Tạo các file cần thiết
Để tạo ra một cấu trúc đơn giản, chúng ta cần tạo ra 3 file:
-
File index.html
- Các thẻ
ul
vàli
sẽ tạo ra menu đơn giản - Phần
script
sẽ nhúng 2 filerouting.js
,app.js
,jquery
và nhúngApp()
sẽ là phần nội dung thay đổi theo đường dẫn
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Routing with pure Javascript</title> </head> <body> <div class="container-app"> <div> <ul> <li><a href="javascript:App.navigateTo('/home')">Home</a> </li> <li><a href="javascript:App.navigateTo('/aboutus')">About US</a> </li> <li><a href="javascript:App.navigateTo('/contactus')">Contact US</a> </li> <li><a href="javascript:App.navigateTo('/services')">Services</a> </li> </ul> </div> </div> <script src="{{cdn}}/jquery.js"></script> <script src="{{localhost}}/js/vendor/routing.js"></script> <script src="{{loclahost}}/js/app.js"></script> <script> $(document).ready(function () { if(App){ App.init(); } }); </script> </body> </html>
- Các thẻ
-
File app.js
- Ở file này, chúng ta sẽ khai báo các router, mối router cần xác định được đường dẫn dẫn tới router đó và dữ liệu trả về.
- Ở các router này, chúng ta có thể dễ dàng lấy được
title
,id
tuỳ thuộc vào từng đường dẫn, từ đó có thể dùng các dữ liệu này làm tham số đểGET
dữ liệu về từ API
var App = {}; var addRoutes = function () { $NB.addRoute('/books/:id', function (params) { console.log('Route is ', params.Title, params.id); }, 'books'); $NB.addRoute('/:category/:id', function (params) { console.log('Route is ', params.Title, params.category, params.id); }, 'category'); $NB.addRoute('/:category/:id/:action', function (params) { console.log('Route is ', params.Title, params.category, params.id, params.action); }, 'category action'); $NB.addRoute(['/', '/:pagename'], function (params) { console.log('Route is ', params.Title, params.pagename); }, 'page'); }; App.init = function () { addRoutes(); $NB.loadController(location.pathname); }; App.navigateTo = function (pageUrl) { $NB.navigateTo(pageUrl); };
-
File js-routing
- File này sẽ chưa các
function
cần thiết dùng trong fileapp.js
//Tự gọi các router tương ứng với các đường dẫn (function (window) { //khai báo một object rỗng var $M = {}; //mảng các router, trong các router sẽ chứa đường dẫn và `function` thực thi $M.RoutingList = []; //Kiểm tra trạng thái của các trang $M.currentPage = ''; //Khai báo class `RoutingClass` và các thuộc tính var RoutingClass = function (u, f, t) { this.Params = u.split('/').filter(function(h){ return h.length > 0; }); this.Url = u; this.Fn = f; this.Title = t; }; //Hàm kiểm tra sẽ trả về 'false' hoặc url params //sẽ phân tích cú pháp url và tìm các tham số từ `location.href` var checkParams = function (urlParams, routeParams) { var paramMatchCount = 0, paramObject = {}; for(var i =0 ; i < urlParams.length ; i++){ var rtParam = routeParams[i]; if(rtParam.indexOf(':') >= 0){ paramObject[rtParam.split(':')[1]] = urlParams[i]; paramMatchCount += 1; } } if(paramMatchCount === urlParams.length){ return paramObject; } return false; }; //thực hiện 'function(s)' theo 'url' tương ứng //cùng với các tham số đã phân tích được //Ví dụ: //: /:page/:pageid //: /home/3434434 //giá trị page=>home và pageid=>3434434 $M.loadController = function (urlToParse) { if($M.currentPage !== urlToParse) { $M.previousPage = $M.currentPage; $M.currentPage = urlToParse; var uParams = urlToParse.split('/').filter(function (h) { return h.length > 0; }); var isRouteFound = 0; for (var i = 0; i < $M.RoutingList.length; i++) { var routeItem = $M.RoutingList[i]; if (routeItem.Params.length === uParams.length) { var _params = checkParams(uParams, routeItem.Params); if (_params) { _params.Title = routeItem.Title; isRouteFound += 1; routeItem.Fn.call(null, _params); } } } }else{ console.log('you are on same page dude!!!!'); } }; //sử dụng chức năng pushSate của browser để điều hướng (thay đổi url) //và thực hiện các hàm tương ứng $M.navigateTo = function (navigateTo) { window.history.pushState(null, null, navigateTo); $M.loadController(navigateTo); }; //thêm 'url' và 'function' vào routing list $M.addRoute = function (urlToMatch, fnToExecute, t) { if(typeof urlToMatch === 'string'){ $M.RoutingList.push(new RoutingClass(urlToMatch, fnToExecute, t)); }else if(typeof urlToMatch && urlToMatch instanceof Array){ urlToMatch.forEach(function (lItem) { $M.RoutingList.push(new RoutingClass(lItem, fnToExecute, t)); }); } }; window.$NB = $M; })(window);
- File này sẽ chưa các
Tổng kết
Như vậy, chỉ cần với 3 file đơn giản trên, bạn đã có thể bắt đầu tạo ra một SPA cho mình. Giờ đây, bạn chỉ cần định dạng lại cái router, viết các hàm render các giao diện tương ứng và đưa chúng vào khung sườn đã có bên trên bằng jquery.
Link tham khảo: https://gist.github.com/muralikrishnat/9c7049fda1a3708c780c