fromHow to gracefully listen for URL changes in a single page application


The principle of single-page application varies from the hash change of url to the change of H5 history to achieve page re-rendering without refreshing. So how to listen for URL changes in a single page application, this article will summarize, how to gracefully listen for URL changes in a single page.

  • Single page application principle
  • Listen for hash changes in urls
  • Listen for events that change the URL by history
  • ReplaceState and pushState behavior listening

Originally posted on my blog: github.com/fortheallli…

Welcome to star

One, single page application principle

The principle of single-page applications is described in detail in our last article on react-Router source code. Here is a brief introduction. Single-page applications allow pages to be rerendered without refreshing, using hash or history in the HTML5 Bom object to change the URL without refreshing the page.

(1) Implement single-page routing using hash

Early front-end routing was implemented with hashes:

Changing the HASH value of the URL will not refresh the page.

Therefore, front-end routing can be implemented using hash to achieve no refresh effect. The hash attribute is in the location object, and in the current page, it can be accessed via:

window.location.hash='edit'
Copy the codeCopy the code

To change the hash value of the current URL. After the above hash assignment, the url of the page changes.

Before: http://localhost:3000 After: http://localhost:3000/#edit

There is a hash value ending in # in the URL, but the page will not refresh even though the hash value of the page changes before and after the assignment, causing the complete URL of the page to change.

In addition to changing the hash value of the current page with window.location.hash, you can also change the HASH value of the HTML with the A tag:

<a href="#edit">edit</a>
Copy the codeCopy the code

(2) Realize front-end routing through history

HTML5’s History interface, the History object is a low-level interface, does not inherit from any interface. The History interface allows us to manipulate the browser session History.

History provides several properties and methods.

Attributes of History:

  • History.length: Returns the number of records in the session History, including the current session page. Also, if a new Tab is opened, the length value is 1
  • History.state: Holds the property object passed by the method that initiates the popState event (more on pushState and replaceState methods later).

Methods the History:

  • History.back(): returns to the previous page in the browser’s session History, similar to the browser’s back button

  • History.forward(): points to the next page in the browser’s session History, similar to the forward button in the browser

  • History.go(): Jumps to a specified page in the browser session History

  • History.pushstate ():pushState pushes the given data onto the browser session History stack. This method takes three parameters, the object, the title, and a list of urls. PushState changes the current page URL, but is not accompanied by a refresh

  • History.replacestate ():replaceState replaces the url of the current session page with the specified data. ReplaceState also changes the URL of the current page, but does not refresh the page.

PushState is similar to repalce in the above methods:

That is, they all change the URL displayed on the current page, but they don’t refresh the page.

Difference:

PushState pushes the browser’s session History stack, increasing history. length by 1, while replaceState replaces the current session History and does not increase history. length.

(3)

You can change the URL without refreshing by changing the hash value, or by changing the repalceState and pushState of history. That leaves a problem to be solved:

How do I listen for URL changes

Not only do we need to change the URL without refreshing, but we also need to listen for the behavior of the URL change and re-render the view based on that behavior. In the next few chapters, I’ll focus on listening for URL changes.

2. Listen for hash changes in urls

Changing the URL with a hash triggers a Hashchange event, and by listening for the Hashchange event, you can catch the behavior of changing the URL with the hash.

window.onhashchange=function(event){ console.log(event); } // or window.adDeventListener ('hashchange',function(event){console.log(event); })Copy the codeCopy the code

Output a HashChangeEvent when the hash value changes. The value of HashChangeEvent is:

{isTrusted: true, oldURL: "http://localhost:3000/", newURL: "http://localhost:3000/#teg", type: "hashchange"..... }Copy the codeCopy the code

By listening for events and changing the hash page to not refresh, we can perform our ability to show and hide different UI displays in the callback function of listening for events, thus implementing front-end routing.

Listen for events that change the URL using history

In the previous chapter, you saw that there are several ways to change a URL using History: history.back (), history.forward (), history.go (), history.pushstate (), and history.replacestate ().

There is also one event supported in history, which is popState. The first thought was that if PopState could listen for url changes caused by all the history methods, we’d be done. Unfortunately:

The history.back (), history.forward (), and history.go () events trigger the popState event. But history.pushState () and history.replacEstate () do not trigger popState events.

If it is history.back (), history.forward (), history.go () then the popState event will be triggered.

window.addEventListener('popstate', function(event) {
     console.log(event);
})
Copy the codeCopy the code

To listen for the corresponding behavior, manually call:

window.history.go();
window.history.back();
window.history.forward();
Copy the codeCopy the code

In addition, clicking the back and forward buttons in the browser also triggers the PopState event, which reads:

PopStateEvent {isTrusted: true, State: null, type: "popState ", Target: Window, currentTarget: Window,... }Copy the codeCopy the code

However, history.pushState () and history.replacestate () do not trigger popState events, for example:

window.addEventListener('popstate', function(event) {
     console.log(event);
})
window.history.pushState({first:'first'}, "page 2", "/first"})
Copy the codeCopy the code

There will be no output in the above example because no listening popState event has occurred.

But history.go and history.back (), which can trigger popState events, refresh the page. We used replaceState and pushState in single-page applications, so there is a problem waiting to be solved:

How do I listen for replaceState and pushState behavior

4. ReplaceState and pushState

In the example above we found that history. replaceState and pushState do not trigger popState events, so how do we listen for these two actions? PopState events can be actively raised within a method. The other is to create a new global event in the method.

Specific measures are as follows:

var _wr = function(type) {
   var orig = history[type];
   return function() {
       var rv = orig.apply(this, arguments);
      var e = new Event(type);
       e.arguments = arguments;
       window.dispatchEvent(e);
       return rv;
   };
};
 history.pushState = _wr('pushState');
 history.replaceState = _wr('replaceState');
Copy the codeCopy the code

This creates two new events called pushState and replaceState that we can listen on globally:

window.addEventListener('replaceState', function(e) {
  console.log('THEY DID IT AGAIN! replaceState 111111');
});
window.addEventListener('pushState', function(e) {
  console.log('THEY DID IT AGAIN! pushState 2222222');
});
Copy the codeCopy the code

This allows you to listen for pushState and replaceState actions.

Refer to the article: stackoverflow.com/questions/4…