⬆️ ⬇️

HistoryAPI: How to write once, and so that the head does not hurt

Good day!



The relatively recent html5 HistoryAPI has already become quite popular. On the Internet you can find many articles on how to raise the work of HistoryAPI, but at the same time they are mostly the same and there are two nuances:



  1. They are organized in such a way that they treat all links equally;
  2. You can shoot yourself a leg and not understand - why.


This article discusses how to organize the work of HistoryAPI so that later not to sell the soul to the devil, so that everything works.



So, what do most articles offer:



Suppose that we have the most starting version of the markup - several navigation links and a block of content:

')

<!DOCTYPE html> <html> <head> <...> </head> <body> <nav> <a href="//<?=$_SERVER['HTTP_HOST']?>"></a> <a href="/about"> </a> <a href="/contact"> </a> </nav> <div id="content"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus, odio. </div> </body> </html> 


And the same averaged minimum suggested js:



 $(document).ready(function(){ $('a').click(function(e){ e.preventDefault(); var url = $(this).attr('href'); $.ajax({ url: url, data: 'ajax=true', success: function(data){ //  ,           $('#content').html(data.content); } }); window.history.pushState(null, null, url); return false; }); $(window).bind('popstate', function(){ $.ajax({ url: history.location, data: 'ajax=true', success: function(data){ $('#content').html(data.content); } }); }); }); 


What is already bad here:



  1. This js equally handles ALL links: external, local, and even links that do not redirect anywhere (say, you made a link that opens a modal window). And in the yard, for a minute, 2017. There are a lot of links that go nowhere on different sites; External links are completely accepted (good form) in a new tab.
  2. As soon as you have a local link in the variable block, you are doomed. Because it will not be processed by your script, and you will not even understand why.


What to do?



Problem 1 is quite easily solved: you only need to catch links with the href attribute (I use links like <a modal_url="/url" modal_header= H Header title title = T Title <> for the links to modal windows>) and with the help of the regular understand local link or not; and depending on it process it differently.



I ran into problem 2 when I was working on raising the HistoryAPI on one of the sites. By the way, this is an online radio, so traveling around the site without updating the page is a crucially important task. What was the problem: The first link to the link after updating the page worked fine. But then some kind of devilishness began: some links continued to work as they should, while others led to a page reload. Only after 2 months of searching for a solution, I finally found that only those links that were not originally on the page, but were there after loading the page, disappear. And they will be satane, because the eavesdropping of the click event is not hung on them.



 //,  : $(document).ready(function(){ $('a[href]').click(function(e){ 


How this code works:



1. You visited the site

2. The script is waiting for the page to load.

3. It scans it and hangs on all links with the href attribute a click event handler.

4. EVERYTHING. On this his work is finished, and he dies.



Suddenly, right? But after all we need to process ALL links ALWAYS.



The first idea is to re-scan the function-update-page - but this does not lead to anything, and the additional code.



The second idea is to return to the idea of ​​onclick = "foo (this)", but we have already decided that we should not do so.



A quick date with Google, and we have a solution :



 $(document).ready(function(){ $(document).on('click', 'a[href]', function(e){ 


This code works a little differently: here the script is looking in the document ... document. And then it will catch all the clicks, responding only to clicks on links with the href attribute. It sounds strange and inexplicably similar to the first option, but it works.



The final option:



This solution will allow you to write a link handler once and forget about the need to add attributes to links when creating new posts; and from the need to explain to everyone who can create new entries on the site, how to insert links correctly.



 $(document).ready(function(){ var pattern = new RegExp("^(https:\/\/"+location.host+"\/|http:\/\/"+location.host+"\/|\/\/"+location.host+"\/|"+location.host+"\/|\/(?!\/))"), // "^\/(?!\/)" - "  /,   -  /" pattern_protocol = new RegExp("^(http:\/\/|https:\/\/|\/\/)"), // , "  "   pattern_lochost = new RegExp("^("+location.host+")"); $(document).on('click', 'a[href]', function(e){ e.preventDefault(); if(!$(this).attr('href')){console.log('no href'); return false;} var url = $(this).attr('href'), isLocal = (pattern.test(url)) ? true : false; if(isLocal){ console.log('Local link: '+url); if(pattern_protocol.test(url)){url = url.replace(pattern_protocol, '');} if(pattern_lochost.test(url)){url = url.replace(pattern_lochost, '');} //     ,    . .., , "https://domain.com/page" -> "/page". //  ,       domain.com/page,     isLocal, //     - domain.com/domain.com/page $.ajax({ //    :      //string data.title //string data.url // bool data.isErrorPage // bool data.hideSidebar //     ,    $('selector').load(data.url+' selector')    . //    -  . url: url, data: 'ajax=true', success: function(data){ reload_page($.parseJSON(data)); } }); window.history.pushState(null, null, url); return false; }else{ console.log('External link: '+url); //       ,    ,     ,   location.href/url (, domain.com/google.com) // http://.    ,   https:// -  . url = (pattern_protocol.test(url)) ? url : 'http://'+url; window.open(url, '_blank'); } }); $(window).bind('popstate', function(){ $.ajax({ url: location.pathname+location.search, data: 'ajax=true', success: function(data){reload_page(data)} }); }); }); 


If you can get links to ftp: // or ssh: // etc. - need to take care of the processing of these links. I did not care, because They will not come across from me.



That's all. Hope it was helpful.

Source: https://habr.com/ru/post/342280/



All Articles