Routes not requested
In traditional development, when the browser clicks on a hyperlink, it sends a request for an html document like a back-end web server, and then the page refreshes. But after starting single page development, it's totally different.
Single page? This concept is difficult to understand. I use a single js as the entire web application, and then manipulate dom changes in that js as a way to implement page changes. Isn't that called a single page? It is! But it's not perfect because it breaks the navigation that comes with the browser. For example, forward, back. So a single-page front-end application has to solve two thingsChanges in content、Navigation changes. This is the basis on which the modern front end was founded.
I'm sure the first contactvue-router
cap (a poem)nuxt
A lot of people are confused about front-end routing. Obviously the link in the browser's address bar changes, so why isn't the browser sending the request out? At least that's what I'm confused about.
Thanks to a browser API, theHistory API. Those who have learned wpf may not be unfamiliar with this stuff, as wpf can also be used to develop browser-based applications with the help of navigation.
navigator
This concept of navigation includes the following features
-
()
Back to previous page -
()
Advance to the next page -
(-2)
Jump to the first two pages
But it's the following three methods that are the key to realizing a single page. Because calling these three api settingslocation
Does not cause the browser to send a page request to the server。
- (data, title, url)
- ()
- (data, title, url)
history
Navigation is a stack, which is the method used to manipulate the stack, enter the stack, exit the stack, and update the top element of the stack. Only this stack holds page related information inside. The most important thing is thatpushState, the rest can be left alone for a while and it doesn't affect the use.
There's also a key one that triggers events when the navigation browser forward and back buttons are clicked. Here, we use js to read the information in the navigation stack and manipulate the dom. this solves the problem of integrating with browser navigation.
The main purpose of these APIs is to support sites like single-page apps that use JavaScript APIs like fetch() to update the page with new content instead of loading an entire new page.
In fact, by this point, the principle of the single-page base implementation is clear.
Implementing a simple single page application
containers
Single page applications need a container, here I am using a div as a container for the page.
<div id="app"></div>
implementation page
web page(architecture) formwork
cap (a poem)js code
Composition. For ease of writing, each is placed in ascript
Tagged in. Declare the page structure in the template with thetype="text/html"
attribute that allows us to get syntax-aware hints. Then define the script, which is really a function. in which the template is read, data is requested, and the page is rendered into the container
<! -- template -->
<script type="text/html" id="page1_html">
<h1> Home</h1>
<h2> This is the first page </h2>
<div id="content"></div>
<button style="background-color: lightcoral;" onclick="('/page2')"> jump to the about page</button>
</script>
<! -- script -->
<script id="page1_js">
function loadPage1(){
// Replace the template page into the container
("app").innerHTML=("page1_html").innerHTML;
// Fetch the data and then generate the content, there may actually be ajax and fetch requests
var data={
text: "This is the content generated using js",
id:1
}; var data={ text: "This is content generated using js", id:1
("content").innerText=(data);
}
</script>.
Front-end Route Scheduling
Templates and scripts alone won't do it, we also need a scheduling algorithm for calling page rendering functions, updating navigation. This is called front-end routing. To make it easier to see, I put the declared pages in an object, which forms a routing table for easy searching. Of course, it's possible not to have this, but to call the script rendering function manuallyloadPage1
。
const route={
page:[
{
url:"/page1",
module:loadPage1
},
{
url:"/page2",
module:loadPage2
}
]
}
Once you have the routing table, you can add the scheduling algorithm to find the corresponding object based on the incoming url, add it to the navigation stack, and then call the script rendering functionloadPageXXX
const route={
routeTo:(url)=>{
var page=(r=>==url);
if(page==null){
alert("File doesn't exist"); }
}
else{
if(==url) return; if(page==null){ alert("File does not exist"); } else{
(,"",);
("You can pass parameters here"); }
}
}
}
// Default jump to the home page
("/page1");
By this one, a single page has been implemented. Clicking the jump button changes the address bar and the page changes. But there's a problem, clicking the browser navigation button doesn't work. This is because we haven't listened to thepopstate
event handles this operation.
Because clicking the navigation button changes the address bar, but what does the page render? This needs to be handled by us. So in this event, we find the page from the routing table, based on the url, and render it.
// Handling forward and backward
("popstate",(e)=>{
var page=(r=>==);
if (page) {
("You can pass parameters here.");
}
})
effect
As you can see, when switching pages, the address bar changes, but no network request is issued
Full Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"> <meta name="viewer"> <header>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>
<title> SPA page</title>
</head>
<body>
<div id="app"> </div>
<! -- Home --> <script type="app"> </div>!
<script type="text/html" id="page1_html">
<h1>Home page </h1>.
<h2> This is the first page </h2>
<div id="content"></div>
<button style="background-color: lightcoral;" onclick="('/page2')"> jump to the about page</button>
</script>
<script id="page1_js">;
function loadPage1(){
// Replace the template page into the container
("app").innerHTML=("page1_html").innerHTML;
// Fetch the data and then generate the content, there may actually be ajax and fetch requests
var data={
text: "This is the content generated using js",
id:1
}; var data={ text: "This is content generated using js", id:1
("content").innerText=(data);
}
</script>
<! -- About page -->
<script type="text/html" id="page2_html">
<h1> About </h1>
<h2> This is the second page </h2>
<div id="content"></div>
<button style="background-color: lightgreen;" onclick="('/page1')"> <Jump to the home page</button>
</script>;
<script id="page2_js">;
function loadPage2(){
// Replace the template page into the container
("app").innerHTML=("page2_html").innerHTML;
// Fetch the data and then generate the content, there may actually be ajax and fetch requests
var data={
text: "Assume this is the site information",
id:2
};
("content").innerText=(data);
}
</script>
<! -- scheduling -->
<script>
const route={
page:[
{
url:"/page1",
module:loadPage1
}, {
{
url:"/page2",
module:loadPage2
}
], { url:"/page2", module:loadPage2 }
routeTo:(url)=>{
var page=(r=>==url);
if(page==null){
alert("File doesn't exist");
}
else{
if(==url) return; if(page==null){ alert("File does not exist"); } else{
(,"",);
("You can pass parameters here"); }
}
}
}
// Handling forward and backward
("popstate",(e)=>{
var page=(r=>==);
if (page) {
("You can pass parameters here");;
}
})
// Default jump to the home page
("/page1");
</script>
</body>
</html>.
concluding remarks
As you can see from the above implementation, a single page application is sending the whole application to the browser and running the program inside the browser. So compared to a single html file, once the application is scaled up, it will be correspondingly large in size. This brings us tochunk
, the concept of chunking the application. Only the scheduling section, the home page, and a few related pages are passed into the browser on the first request, and subsequent files are transferred when the subsequent request reaches a page that has not been transferred.
Since our pages are all in one web page, essentially a web server is transferred to the browser, with js controlling the rendering when navigating. So transition effects, filters, request pipelines, middleware, things that web servers have are possible to implement in web pages.
But the single page application SPA, the web server owes everything to that key feature provided by the browser.History API