Before the introduction

Work recently a bit busy, write slowly, when I finished writing the article for publication, found that the nuggets are just has an essay on the front-end routing, and write the detailed than me, but worked so hard to write, do not want to be deleted, say my routing style is pure personal ideas, so I still crustily skin of head hair.

preface

Vue, React, angular all have their own routers. Do you know how routers work? If you don’t know, please write a simple front-end route with me to learn about it.

Two ways to implement routing

  1. Hash pattern
  2. The history mode

Disadvantages:

Hash: ugly (address bar requires an extra #), with a hash in some special scenarios, such as wechat Pay callback

History: Poor compatibility, direct access to 400, unless the backend or server processing

The basic principle of

Hash is based on listening for hashchange events, history is based on pushState and popState,

implementation

Since history is not compatible and the implementation methods are basically the same, this paper uses hash mode to implement history, while only different parts of history are implemented.

<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<input type="button" onclick="hashPush('index')" value="goto index">
</body>
<script>
    // Page jump
    function hashPush(url) {
        location.hash = "#" + url
    }

    // Listen for hash changes
    window.addEventListener('hashchange'.function (e) {
        console.log('Current hash address', location.hash.slice(1) | |"/")})</script>
</html>
Copy the code

This is the simplest implementation of the Hash mode. If you look at the console, whether you click the jump button or click the browser’s forward/back button, the console will output the corresponding ‘URL’ of the current page. With the ‘URL’, you can conditionally render the content

Add two divs, one for login and one for index

<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            margin: 0;
            padding: 0;
        }
        #login.#index{
            width: 100%;
            height: 100%;
            display: none;
        }

        #login{
            background: #f5f5f5;
            display: block;
        }

        #index{
            background: #aaddff;
        }
    </style>
</head>
<body>

<! -- Login page -->
<div id="login" class="component">
    <input type="button" onclick="hashPush('index')" value="Login">
</div>

<! - home page - >
<div id="index" class="component">
    <input type="button" onclick="hashPush('login')" value="Log out">
</div>

</body>
<script>

    // Page jump
    function hashPush(url) {
        location.hash = "#" + url
    }

    // Listen for hash changes
    window.addEventListener('hashchange'.function (e) {
        let url = location.hash.slice(1) | |"/"
        console.log('Current hash address', url)
        setVisible(url)
    })

    // Display the contents corresponding to the routing address and hide other contents
    function setVisible(url) {
        let components = Array.from(document.body.querySelectorAll(".component"))
        components.map(item= > {
            if(item.id===url) {
                console.log('show',item.id)
                item.style.display = 'block'
            } else {
                console.log('hide',item.id)
                item.style.display = 'none'}})}</script>
</html>

Copy the code

This way, we can display different contents based on different hash addresses, which is a bit like routing. There are many ways to pass parameters. The most common and popular way to pass parameters is query String. The Query String is actually quite simple, parsing the URL.

    // Listen for hash changes
    window.addEventListener('hashchange'.function (e) {
        let url = location.hash.slice(1) | |"index"
        / / url
        let questionIndex = url.indexOf("?")
        let path, query
        if(questionIndex >= 0){
            path = url.substr(0,questionIndex)
            let queryString = url.substr(questionIndex+1)
            let queryArray = queryString.split("&")
            let queryObject = {}
            queryArray.map(str= > {
                let equalIndex = str.indexOf("=")
                if(equalIndex > 0) {
                    let key = str.substr(0,equalIndex)
                    let value = str.substr(equalIndex+1)
                    queryObject[key] = value
                }
            })
            query = queryObject
        } else {
            path = url
            query = {}
        }
        
        console.log('Parameters received', query)
        setVisible(path)
    })
Copy the code

In this way, we can get the Query String passed on the URL, and we also solve the route resolution bug.

An even easier way to pass a parameter is to set a global variable called param, and then assign to param whenever you need to pass a value

    // Set a global variable
    var param = {}
Copy the code
    // Page jump
    // Add args
    function hashPush(url, args) {
        location.hash = "#" + url
        param = args
    }
Copy the code

It’s a global variable, so you can use param anywhere you want, but there’s a disadvantage to using a global variable directly, which is that when you hit the return button, you can’t save the variable, and when you return a Query string, because it’s in a URL, We can get the query string from the previous page. Is there a way to make global variables hold the previous page’s parameters as well? Let’s modify the code a little bit

    // Set a global variable
    var param = {}
Copy the code
    // Page jump
    // Add args
    function hashPush(url, args) {
        location.hash = "#" + url
        // If args is passed, create an object under the param object with the same name as the current URL and assign args to it
        if(args) {
            param[url] = args
        }
    }
Copy the code

So when we do hashchange, we can locate the parameters of the page based on the URL.

    // Listen for hash changes
    window.addEventListener('hashchange'.function (e) {
        // omit other code
        args = param[path] || {}
        // omit other code
    })
Copy the code

Now that we’ve implemented a hash route, let’s look at the history route.

The history mode

The history mode relies on calling the history.pushState() method and listening for popState events.

The history.pushstate () method takes three arguments:

  1. Data to pass (parameters)
  2. The title for the page (poor compatibility and almost useless)
  3. url

Let’s look at the invocation example

    history.pushState({id:1}, 'I'm the page title', url)
Copy the code

Note that the popState event is not triggered when pushState is pushed, but only when it is pushed forward or backward. After pushState, you need to manually set the page state. In the example above, we need to do this

    history.pushState({id:1}, 'I'm the page title', url)
    setVisible(url)
Copy the code

Then listen for the PopState event to capture the forward/backward

 window.addEventListener('popstate'.function (e) {
     // e.state is the first argument passed when you pushState
     let state = e.state || {}  
     let url = state.target.location.pathName
     // Do something else with the parameters
  })
Copy the code

The last

The final implementation code of this article has been put on Github, students who want to see the effect directly, can go up directly copy, run.

If you find this article useful, please add a star to github of this article. Thank you very much

In addition, there are other front-end tutorials and components available on Github for those who are interested. Your support is my biggest motivation.


Other links

  1. Use proxy to implement a more elegant VUE
  2. Three lines of code implement a simplified version of promise
  3. Vuex is super easy, just 3 steps
  4. Vuex is super easy. Drink those three steps, then there are three more
  5. Start from scratch with a Vue toast popover component
  6. Inheritance in JS (part 1)
  7. Inheritance in JS
  8. The prototype object in JS
  9. JS method to create an object
  10. My moment is too heavy? Try Miment – an ultra-lightweight JS time library
  11. Meituan applet framework MPvue introductory tutorial
  12. Meituan small program framework mpvue(花名 : no friends) squat guide
  13. A TOAST popup component mpTOAST based on MPVUE