What is? SPA?

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

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




* Reduce server pressure.
If notSPA, So every time we switch pages, A request will be sent to the server, The server returns ahtml file; But if usedSPA, When switching, No request server required, Just through the localjs 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, increaseapp Using fluency of.
Have donespa All of my classmates know, Usespa after, The page is very smooth when switching, There's no sense of constant renewal, It's a very quick response, becausejs Very fast, thereforejs When doing local routing, It will be very fast.

SPA How to implement routing?

   For now, Whether it isvue, stillreact,spa The routing implementation of is nothing more than the following two:

* hash mode. Uselocation.hash andhashchange Event implementation routing. 
* history api. Usehtml5 Ofhistory api Realization, MainlypopState Events, etc..
  hash It's still used a lot, But this wayurl It's ugly, Will appear #; andhistory
api We can solve this problem very well, But back end configuration is required, And because it'shtml5 Mediumapi, So compatibility is not very good, You need to identify your users when using, Make another decision..



SPA Routing implementationhash

        Do it yourself, Have ample food and clothing!
Let's write one ourselvesrouter, Maybe alignment understanding will be more clear. commonly, We are usingvue andreact Ofrouter 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"> Red</a> </div>
<script>// EstablishRouter Constructor // currentHash For the presenthash 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 aRouter Constructor, Initialize the currenturl And oneroutes object.

   Then three methods are defined:

* route Method --- This method is used to instantiaterouter After object, Registration routing, 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 especialhashchange Event, very important. 
   The effect is as follows:















SPA Routing implementationhistory API

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

   Used abovehash It's a good way to implement routing, But there are also some problems, It's ugly.~
If used in wechat, Out of sighturl 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. 

   stayhtml5 Mediumhistory api There are two wayshistory.pushState() andhistory.replaceState(), Contain
An eventhistory.onpopstate, Let's start with a brief introduction:

history.pushState(stateObj, title, url)

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



   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 usedfile:// 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 '

becausepushState Ofurl And currentUrl Must be homologous, andfile:// There is no homology in the form of, So we have to usehttp://localhost Way.
<!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"> Red</a>
</div> <script>// EstablishRouter Constructor function Router() { this.currentRoute = ''; this
.routes = {}; this.init(); } // Register routing functions Router.prototype.route = function (path,
callback) {// according totype type, Select the appropriatehistory 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 ishttp://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 alllink Tag binding event var historyLinks = document.querySelectorAll('.history-link');
for (var i = 0, len = historyLinks.length; i < len; i++) {
historyLinks[i].onclick= function(e) { // Deter default e.preventDefault();
self.currentRoute= e.target.getAttribute('href');
self.refresh(self.currentRoute,1); } } } </script> <script> var wrap =
document.querySelector('.router-wrap'); // instantiationRouter window.Router = new
Router();// Registration routing, 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!