Location>code7788 >text

Backend says what's going on with single page SPA and front-end routing

Popularity:374 ℃/2024-07-26 23:06:14

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 contentNavigation changes. This is the basis on which the modern front end was founded.

I'm sure the first contactvue-routercap (a poem)nuxtA 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 settingslocationDoes not cause the browser to send a page request to the server

  • (data, title, url)
  • ()
  • (data, title, url)

historyNavigation 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) formworkcap (a poem)js codeComposition. For ease of writing, each is placed in ascriptTagged 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 thepopstateevent 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

image

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