What is?  SPA?

  SPA It's a single page app , Namely single page application, You can find it by looking at the code , There is only one website Html file .

       github address <https://github.com/zzw918/spa-router>

 

 

WHY SPA?

* Reduce server pressure .
If not SPA, So every time we switch pages , Will send a request to the server , The server returns a html file ; But if used SPA, When switching , No request server required , Just through the local js Just switch . And the server does not need to configure the route , Complete front and rear end separation , The significance of this for division of labor and cooperation can be imagined .
* Enhance the user experience , increase app Using fluency of .
Did it spa All of my classmates know , use spa after , The page is very smooth when switching , There's no sense of constant renewal , It's a very quick response , because js Very fast , therefore js When doing local routing , It will be very fast .
 

SPA How to implement routing ?

   For now , Whether it is vue, still react,spa The routing implementation of is nothing more than the following two :

* hash mode . use location.hash and hashchange Event implementation routing . 
* history api. use html5 Of history api realization , Mainly popState Events, etc .
  hash It's still used a lot , But this way url It's ugly , Will appear #; and history
api We can solve this problem very well , But back end configuration is required , And because it's html5 In api, So compatibility is not very good , You need to identify your users when using , Make another decision .

  

 

SPA Routing implementation hash

        Do it yourself , have ample food and clothing !
Let's write one ourselves router, Maybe alignment understanding will be more clear . commonly , We are using vue and react Of router When , It's not hard to see that they're constructors , Then generate an instance , Object oriented approach .

   Of course, we also need to use the object-oriented method to realize it , Scalability of this approach , Maintainability will be better .

  github address <https://github.com/zzw918/spa-router/tree/master/hash>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">
<title>router</title> <style> html, body { width: 100%; height: 100%; margin: 0
; } div.router-wrap { width: 100%; height: 100%; background: #fefefe; } a {
padding: 10px; color: pink; font-size: 25px; font-weight: bold; text-
decoration: none; }</style> </head> <body> <div class="router-wrap"> <a href="
#/black"> black </a><br> <a href="#/green"> green </a><br> <a href="#/red"> gules </a> </div>
<script>// establish Router Constructor // currentHash Is current hash value ,routes Is a path object function Router() {
this.currentHash = '/'; this.routes = {}; } // Registration path , Each path corresponds to a callback function .
Router.prototype.route = function (path, callback) { this.routes[path] =
callback || function () { alert(' No callback function defined !'); } } // Update page functions
Router.prototype.refresh = function () { this.currentHash = location.hash.slice(
1) || '/'; this.routes[this.currentHash](); } // initialization Router.prototype.init =
function () {var self = this; window.addEventListener('load', function () {
self.refresh(); },false); window.addEventListener('hashchange', function () {
self.refresh(); }); }</script> <script> var wrap = document.querySelector('
.router-wrap'); window.Router = new Router(); Router.route('/', function () {
wrap.style.backgroundColor= '#fefefe'; }); Router.route('/black', function () {
wrap.style.backgroundColor= 'black'; }); Router.route('/green', function () {
wrap.style.backgroundColor= 'green'; }); Router.route('/red', function () {
wrap.style.backgroundColor= 'red'; }); Router.init(); </script> </body> </html>
 

   The idea of the above code is not difficult to understand .

   First create a Router Constructor , Initialize the current url And a routes object .

   Then three methods are defined :

* route method --- This method is used to instantiate router After object , Register route , For different routes , Execute different callback functions .
* refresh method --- When routing is switched , Execute this method to refresh the page .
* init method --- After registering routes , Execute the method , This method mainly registers two events , in especial hashchange event , very important . 
   The effect is as follows :



 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPA Routing implementation history API

  github address <https://github.com/zzw918/spa-router/tree/master/history%20api>

   Used above hash It's a good way to implement routing , But there are also some problems , It's just ugly ~
If used in wechat , Out of sight url It doesn't matter , But if you use it in a normal browser, you will encounter problems . So here we use history api To achieve . 

   stay html5 In history api There are two ways history.pushState() and history.replaceState(), contain
An event history.onpopstate, Let's start with a brief introduction :

history.pushState(stateObj, title, url)

* stateObj Is a state object , This object can be popstate Event read to , You can also history Object .
* title As title , But the browser hasn't been implemented yet , Because it is a string , So we use ‘’ To replace .
* url Is the path . Generally set as relative url, Absolute path needs to ensure homology . 
  pushState Press a history into the browser's history stack , So here push and pop It's easier to understand .

 

history.replaceState()

   This is easier to understand , All parameters accepted are the same , The function is to replace the records in the current history stack .

  

onpopstate event   

   Forward in browser , Triggered on reverse , This event is usually triggered when the pointer in the history stack changes .

 



 

  Before the test , Need to know such a thing :  Tests must be performed on the local server , If using file:// How to open a page , The following will happen :
Uncaught SecurityError: A history state object with URL '
file:///C:/xxx/xxx/xxx/xxx.html' cannot be created in a document with origin '
null'.
 

because pushState Of url And current Url Must be homologous , and file:// There is no homology in the form of , So we have to use http://localhost How .
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">
<title>router</title> <style> html, body { width: 100%; height: 100%; margin: 0
; } div.router-wrap { width: 100%; height: 100%; background: #efefef; } a {
display: inline-block; padding: 10px; color: pink; font-size: 25px; font-
weight: bold; text-decoration: none; } </style> </head> <body> <div class="
router-wrap"> <a href="/black" class="history-link"> black </a><br> <a href="/green"
class="history-link"> green </a><br> <a href="/red" class="history-link"> gules </a>
</div> <script>// establish Router Constructor function Router() { this.currentRoute = ''; this
.routes = {}; this.init(); } // Register routing functions Router.prototype.route = function (path,
callback) {// according to type type , Select the appropriate history api. this.routes[path] = function (type) {
if (type == 1) { history.pushState({path: path}, '', path); } else if (type == 2
) { history.replaceState({path: path},'', path); } callback(); } } // Update page
Router.prototype.refresh = function (path, type) { this.routes[path](type); } //
initialization Router.prototype.init = function () { var self = this; //
Reload function , The host used here is http://localhost:8088/ window.addEventListener('load', function
() { self.currentRoute= location.href.slice(location.href.indexOf('/', 8));
console.log(self.currentRoute); self.refresh(self.currentRoute); });//
Trigger function when user clicks forward / backward button window.addEventListener('popstate', function () { console.log('
history.state.path:', history.state.path); self.currentRoute =
history.state.path; self.refresh(self.currentRoute,2); }, false); //
For all link Tag binding event var historyLinks = document.querySelectorAll('.history-link');
for (var i = 0, len = historyLinks.length; i < len; i++) {
historyLinks[i].onclick= function(e) { // Block default e.preventDefault();
self.currentRoute= e.target.getAttribute('href');
self.refresh(self.currentRoute,1); } } } </script> <script> var wrap =
document.querySelector('.router-wrap'); // instantiation Router window.Router = new
Router();// Register route , Realize corresponding functions Router.route('/', function () {
wrap.style.backgroundColor= '#efefef' }); Router.route('/black', function () {
wrap.style.backgroundColor= 'black'; }); Router.route('/green', function () {
wrap.style.backgroundColor= 'green'; }); Router.route('/red', function () {
wrap.style.backgroundColor= 'red'; }); </script> </body> </html>
 

 

node Part of the code is as follows :
var express = require('express'); var path = require('path') var app =
express(); app.get('/', function (req, res) {
res.sendFile(path.resolve(__dirname,'./www/history.html')); }) app.get('*',
function (req, res) { res.sendFile(path.resolve(__dirname,'./www/history.html'
)); });const port = 8088; var server = app.listen(port, function () {
console.log(" Access address is http://localhost:" + port) });
 

 

The final effect is as follows :





 

And it can realize the basic forward and backward functions . 

 

 

 

 

 

Original article , Without permission , No reprint !