As a single dog, really do not know what valentine’s day 😂, ah calculated, steadfastness to write an article, if feel the article is good to give a praise.

Hash mode:

This pattern is relatively simple. When we change the hash of an HTML file, that is, the URL with a #value after it, the browser will not send the request, and even if it does send the request (such as refreshing the page) it will not carry the hash. This feature allows us to listen for changes in the hash and manipulate the DOM according to the # argument to jump to the corresponding page. Here are three important things to know:

  • Modifying the hash can be done with the A tag,<a href="#1"> Display 1</a>
  • Listen for hash changes through the Hashchange event
  • Hash retrieves the hash using window.location.hash





<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
    <style>
        #page1.#page2.#page3.#page4.#page404 {
            display: none;
        }

    </style>
    
</head>
<body>
    <a href="# 1">According to 1</a>
    <a href="# 2">According to 2</a>
    <a href="# 3">According to 3</a>
    <a href="# 4">According to 4</a>
    <hr>
    <div id="app">
    </div>
    <div id="page1">1</div>
    <div id="page2">2</div>
    <div id="page3">3</div>
    <div id="page4">4</div>
    <div id="page404">404 Not Found</div>

    <script>
        // Get all the pages
        let page1 = document.querySelector('#page1');
        let page2 = document.querySelector('#page2');
        let page3 = document.querySelector('#page3');
        let page4 = document.querySelector('#page4');
        // Create a hash table
        const routeTable = {
            '1': page1,
            '2': page2,
            '3': page3,
            '4': page4
        }

        function route() {
            // Get the current hash
            let number = window.location.hash.slice(1);
            number = number || 1;
            // Get the current page based on the hash
            let page = routeTable[number.toString()];
            page = page || document.querySelector('#page404');
            page.style.display = 'block';
            // Get the container
            let app = document.querySelector('#app');
            if(app.children.length > 0) {
                app.innerHTML = ' ';
            }
            // Render the page
            app.appendChild(page);
        }


        // Render the main page initially
        route();
        // Listen for hash changes
        window.addEventListener('hashchange'.function(){
            route();
        })
    </script>
</body>
</html>
Copy the code



It is compatible, but SEO is not friendly because modifying hash does not send a request to the browser.

The history mode:

PushState or history.replaceState, and then the popState event is triggered according to the MDN document. We simply listen for the popState event to get location. pathName and modify the content of the page with the corresponding parameters as above. Then I did a search on the Internet, and the main method for modifying a URL without sending a request is window.history:

  • Back () : moves back to the previous route.
  • Forward () : forward to the next route, if any;
  • Go (number) : indicates that a route is entered. The positive value indicates forward and the negative value indicates backward.
  • PushState (obj, title, url) : advances to the specified URL without refreshing the page;
  • ReplaceState (obj, title, URL) : Replaces the current route with the URL without refreshing the page.

The difference is that the first three use the browser’s history and do not generate a new URL, while the latter two allow the browser to store the new URL into the history. If the pushState is IE10 or higher, < can be used. Br /> Also note that history mode must work with the back end, because although history.pushState does not reload the page after changing the URL, if we refresh the page we will send the request with the new URL, and if the back end URL has not been updated at this point it will return 404. Let’s look at the history.pushState API, which adds a new history to the browser without refreshing the page. And it’s done in homologous mode, which means it just adds new content after the current URL. Here’s the MDN documentation for you to look at it in detail. It also explicitly states that history.pushState will trigger popState. Ignoring the first two parameters, we’ll focus on the third parameter url, which is more basic:

window.history.pushState(state,title,url)

Copy the code
  • State: Data that needs to be saved. This data can be retrieved in event.state when the popState event is triggered
  • Title: title, basically useless, usually pass null
  • Url: Sets a new history URL. The origin of the new URL must be the same as the origin of the current URL, otherwise an error will be thrown. A URL can be an absolute path or a relative path.


/ / if the current url is https://www.baidu.com/a/,
PushState (null, null, './qq/'),
/ / into https://www.baidu.com/a/qq/,
PushState (null, null, '/qq/');
/ / into https://www.baidu.com/qq/
Copy the code

From this we can see that the third argument to pushState can be a relative address. Having said that, I think you should have a general understanding of the history mode. Think this article is so happy to end? But there would be no point in Posting this article if all went well. I then tried to write a simple case like the above hash. I knew I didn’t have the backend to work with, but I thought I’d just call pushState and start the popState event to prove it would work, but…

	history.pushState(null.null.'# 333');
        window.addEventListener('popstate'.function(){
            console.log(location.pathname);
        })
Copy the code


I wrote a little case, by reason if I passpushStateThe modifiedhashIf the page is refreshed, the request will not be sent but the Popload event will be triggered to obtain the corresponding Pathname. But I was fooled. There was nothing on the consoleThe output?????



 

I think this is the first of the New YearBUG? So I can only continue to helplessly painful search on the Internet, and finally found an article and I met the same problem.



Although the originalpopstateThe event also carries onestateHowever, it was unable to passpushStatewithreplaceStateTriggered, butGo () back() forward()It can be triggered.



So I immediately ran an experiment:

        window.addEventListener('popstate'.function(){
            console.log(location.pathname);
        })
        setTimeout(function(){
            history.back();
        },1000)
Copy the code


 



It worked, but how do we actually listen for pushState if popState can’t listen for pushState’s changes to the URL? Now comes the real point…



We need to create a custom eventnew Event('pushState')Manually trigger our custom event when we call pushState, and then listen for the custom event instead of the popState event.



For those of you who are not familiar with custom eventsMDN EventWe can think of it as an event that we define ourselves, like click, and then we can bind it to an element. I’ll go through this example firstaddEventListenerBound to thewindowOn.



So once we bind, we need to fire the event of the bind, what we bind to what we need to fire it with, what is the API that fires the eventdispatchEvent. The difference between this and our manipulation of DOM triggering events is that this issynchronous. You can look at itMDN dispatchEvent.

        let oBox = document.querySelector('.box');
        const andyevent = new Event('andyEvent')
        window.addEventListener('andyEvent'.function(){
            console.log('An event created by Andy triggered');
        })
        setTimeout(function(){
            window.dispatchEvent(andyevent);
        },1000)
Copy the code

With that said, it’s just a matter of understanding what the new Event() and dispatchEvent() apis do. Then we create a custom pushState Event internally by overriding the history.pushState method. Our custom event is triggered when we call pushState, so we can listen externally. That’s the finished code.

        // Override pushState and replaceState methods
        function addStateListener(){
            function listener(type){
                let origin = history[type];
                return function(){
                    let newOrigin = origin.apply(this.arguments);
                    let stateEvent = new Event(type);
                  	The reason for adding arguments is that you can get arguments passed to the event when listening for the event firing
                    stateEvent.arguments = arguments;
                    window.dispatchEvent(stateEvent);
                    return newOrigin;
                }
            }
            history.pushState = listener('pushState');
            history.replaceState = listener('replaceState');
        }
        addStateListener()
Copy the code

Actual test:

	addStateListener()
        // Listen on pushState and replaceState
        window.addEventListener('pushState'.function(e){
            console.log(location.pathname,e.arguments[2]);
        })
        window.addEventListener('replaceState'.function(e){
            console.log(location.pathname,e.arguments[2]);
        })
        // Use pushState and replaceState to modify the URL
        history.pushState(null.null.'# 333')
        history.replaceState(null.null.'# 666')
Copy the code

  



 



Well, this is really the end of itlocation.pathnameTo intercept the string, or just go through as aboveargumentsTo get the parameters of the modified part of the URL, and to control the display and hiding of certain parts of the page, rather than the concrete display of hash.



Finally:

Finally, the article was first published in my wechat public number [South orange front]. There are many exciting articles here. Welcome to pay more attention to the content of the article.

Reference:

Mozzie: In-depth understanding of the hash and History routes in the front end