Good day, ladies and gentlements! Today I'm going to tell you about HTML5 history management. This article will be useful for beginners, for thos who want understand how this feature works and what we can do with it. If you interested - come closer.
First things first. What is the HTML5 history is? Here is definition from MDN
We need a plan. That will be a simple test application with header, navigation and content area, that will be reloaded when we navigate to different menu items. We must catch all clicks on link tags and prevent native transitions. Then we need to implement routing based on history management to load something in the content area. Another thing - all http requests, except requests for static resources, such as JS/CSS/images must be forwarded to our index page where our SPA resides. Why we need this? We need this because if you navigate to some page and reload it with F5 you will get a 404 error. Because all you have on your server is your index page and static resources. So we need to load it to any request.
So in few word
And the styles is:
Good! Lets get to the second!
It will prevent all clicks on the link tags from native transitions.
Ok, next
As you can see i added toutes object, that in fact a plain JS object, taht maps an request path to content that must be loaded to content area. On every link click we get it href attribute and push it to history stack as a part of state object. Also I added a default route , that will be used if no one of defined routes is not acceptable to current requst path. An the last thing - we must make our route on page load. So we do it. Ok, we need to run this on our index page.
As you can see, everything what resides in static folder will be loaded as is. Everything else will be forwarded to index.jsp page.
And a test!
Works nice, I think.
GitHub repo with sources is here.
If you are use my materials, please make the link to my blog. Be polite!)
Thank you for watching and goodbye!
First things first. What is the HTML5 history is? Here is definition from MDN
The History
interface allows manipulation of the browser session history, that is the pages visited in the tab or frame that the current page is loaded in.
So, in simple words gistory interface allows us to change (and save changes) URI of our website's pages without full page reloading. That way we can build SPA (Single Page Application), that will be indexed by search robots as regular website. Lets try to make it!We need a plan. That will be a simple test application with header, navigation and content area, that will be reloaded when we navigate to different menu items. We must catch all clicks on link tags and prevent native transitions. Then we need to implement routing based on history management to load something in the content area. Another thing - all http requests, except requests for static resources, such as JS/CSS/images must be forwarded to our index page where our SPA resides. Why we need this? We need this because if you navigate to some page and reload it with F5 you will get a 404 error. Because all you have on your server is your index page and static resources. So we need to load it to any request.
So in few word
- Make a simple page with header, navigation and content area;
- Prevent all native link transitions;
- Create inner SPA routing ased on history managent;
- Forward requests to our index page.
I'm java developer, so I make a web java app, that will be tunned on tomcat.
1. Make a simple page with header, navigation and content area:
Done! =)<!DOCTYPE html> <html> <head> <title>HTML5 Features</title> <link rel="stylesheet" href="static/css/styles.css"/> </head> <body> <h2 class="title">HTML5 Features</h2> <nav class="navigation"> <ul class="navigation__list"> <li class="navigation__list_item"><a href="/page_1">Page 1</a></li> <li class="navigation__list_item"><a href="/page_2">Page 2</a></li> <li class="navigation__list_item"><a href="/page_3">Page 3</a></li> </ul> </nav> <main id='content' class="content"> Page 1 </main> </body> </html>
And the styles is:
*{ margin:0; padding:0; } body{ box-sizing: border-box; } .title{ background: #66a5ee; margin:0; padding: 10px; display:block; color:#fff; height:25px; } .navigation{ display: block; float:left; width:100px; padding:10px 25px; background: #eee; } .navigation__list_item{ list-style: none; margin: 10px 0; } .navigation__list_item a{ font-size: 18px; } .content{ padding:25px; display:block; float:left; }
Good! Lets get to the second!
2. Prevent all native transitions.
Create a js file called router.js and fill with following code:
var router = function () { var links = document.getElementsByTagName('a'); for (var i = 0; i < links.length; i++) { links[i].addEventListener('click', function (event) { event.preventDefault(); }); } }
It will prevent all clicks on the link tags from native transitions.
Ok, next
3. Create inner SPA routing ased on history managent.
I'll do it in the same js file:
var router = function (routes) { var links = document.getElementsByTagName('a'); var routes = routes || {}; routes['else'] = "There is nothing to watch!"; for (var i = 0; i < links.length; i++) { links[i].addEventListener('click', function (event) { event.preventDefault(); var url = event.target.getAttribute('href'); var state = {url: url}; history.pushState(state, '', url); stateChange(state); }); } window.onpopstate = function (event) { stateChange(event.state); }; window.onload = function () { var pn = window.location.pathname; if (history.state) { if (history.state.url == pn) stateChange(history.state); else { history.pushState({url: pn}, '', pn); } } else { history.pushState({url: pn}, '', pn); stateChange({url: pn}); } } function stateChange(state) { content = routes[state.url]; if (content == undefined) { content = routes['else']; } document.getElementById('content').innerHTML = content; } }
As you can see i added toutes object, that in fact a plain JS object, taht maps an request path to content that must be loaded to content area. On every link click we get it href attribute and push it to history stack as a part of state object. Also I added a default route , that will be used if no one of defined routes is not acceptable to current requst path. An the last thing - we must make our route on page load. So we do it. Ok, we need to run this on our index page.
<head> <title>HTML5 Features</title> <link href="static/css/styles.css" rel="stylesheet"></link> </head> <body> <h2 class="title"> HTML5 Features</h2> <nav class="navigation"> <ul class="navigation__list"> <li class="navigation__list_item"><a href="https://www.blogger.com/page_1">Page 1</a></li> <li class="navigation__list_item"><a href="https://www.blogger.com/page_2">Page 2</a></li> <li class="navigation__list_item"><a href="https://www.blogger.com/page_3">Page 3</a></li> </ul> </nav> <main class="content" id="content"> Page 1 </main> <script src="static/js/html5_router.js"></script> <script> router({ "/": "Page 1", "/page_1": "Page 1", "/page_2": "Page 2", "/page_3": "Page 3" }); </script> </body> </html>
4. Forward requests to our index page.
As I said - I making a java app. So forwarding will be implemented with Filter object:
public class FrontFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) req; String path = httpServletRequest.getRequestURI(); if (path.startsWith("/static")) { filterChain.doFilter(req, res); return; } RequestDispatcher requestDispatcher = req.getRequestDispatcher("/"); try { requestDispatcher.forward(req, res); } catch (ServletException e) { } catch (IOException e) { } } public void destroy() { } }
As you can see, everything what resides in static folder will be loaded as is. Everything else will be forwarded to index.jsp page.
And a test!
Works nice, I think.
GitHub repo with sources is here.
If you are use my materials, please make the link to my blog. Be polite!)
Thank you for watching and goodbye!
Комментарии
Отправить комментарий