This article will teach you how to write history by hand, focusing on understanding how it works.

History is a JavaScript library that lets you easily manage session history anywhere your JavaScript is running

1. Introduction

While History is maintained by Facebook, the React-router relies on history, as opposed to the browser’s window.history, which contains window.history. An API that allows developers to use History in any environment (e.g. Node, React Native, etc.). In this article, history refers to the repository object and window.history refers to the browser object.

This reading is divided into five parts, respectively for the introduction, use, principle, start, summary, recommended reading order haha.

The enclosed address

  1. history
  2. History Resolves the Github address
  3. History Github address of demo
  4. Managing session history (digging gold)

2. Use


      
<html>
  <head>
    <script src="history.js"></script>
    <script>
      var createHistory = History.createBrowserHistory

      var page = 0
      // createHistory Creates the required history object
      var h = createHistory()

      // h.lock triggers to inform the user that the address bar is about to change before the address bar changes
      h.block(function (location, action) {
        return 'Are you sure you want to go to ' + location.path + '? '
      })

      // h.listen listens for changes to the current address bar
      h.listen(function (location) {
        console.log(location, 'lis-1')})</script>
  </head>
  <body>
    <p>Use the two buttons below to test normal transitions.</p>
    <p>
      <! -- h.paush -->
      <button onclick="page++; h.push('/' + page, { page: page })">history.push</button>
      <button onclick="h.goBack()">history.goBack</button>
    </p>
  </body>
</html>
Copy the code

The history usage:

  1. blockInterception before address change;
  2. listenerUsed to monitor the change of the address bar;
  3. pushAdd new history;
  4. replaceReplace the current history;
  5. go(n)Jump to a historical record.
  6. goBackReturns the last historical record.

Principle 3.

Explanation:

  1. push,replace,go,goBack: warehousehistoryThe method of
  2. pushState,replaceState:window.historyIs used to modifywindow.historyThe historical record
  3. popstate: Listens for historical changeswindow.addEventListener('popstate', callback)
  4. forceNextPop: user-defined variable, used to determine whether to skip the pop-up box
  5. allKeys: custom variable, which is synchronized with history. This array is maintained every time the history is modified so that you can return to the last history when the pop-up box is hit Cancel
  6. go(toIndex - fromIndex): Returns the last historical record when a dialog box is displayed to cancel

The POPState event is triggered when the active history entry changes. Note that a call to history.pushState() or history.replacEstate () does not trigger a popState event. This event is triggered only when a browser action is taken, such as when the user clicks the browser’s back button (or calls history.back() in Javascript code)

Route 1 (push and replace) :

  1. The user callspush;
  2. Pop-up pop-up box;
    1. Click ok button:
      1. callwindow.history.pushStateAdd history to thekeyStored in thewindow.historyNote that this is not triggered at this timepopstateListener function);
      2. Address change;
      3. Maintain custom variablesallKeysTo addkeytoallKeysThe array.
    2. Click cancel button: no operation.

Line 2 (GO and goBack) :

  1. The user callsgo;
  2. Modifying historywindow.history, address change;
  3. The triggerpopstateHistory listener function (if boundpopstateListener function);
  4. Pop-up pop-up box;
    1. Click ok button:
      1. updatehistory(to ensurehistoryIs the latest information, for examplehistory.locationIs the current address information.
    2. Click the cancel button (because the address has changed in the second step, click the cancel intention of the pop-up box to return to the previous record) :
      1. To calculatetoIndex: Indicates the address before the jumphistory.locationThe value of theta, because theta at this timehistory.locationNot updated is old value);
      2. To calculatefromIndex: of the current addresskey;
      3. To calculate the difference between the two, callgoMethod jumps back to the last history.

This is basically the principle of history, some students should be confused, call the pop-up box can be placed before call go, the same effect, and the code will be more concise and do not need to maintain the array of allKeys. I had this question before, but come to think of it, the go function doesn’t contain all history changes, and if the user swipes left to go back to the previous page, it won’t work. Therefore, the popup box can only be triggered after the change of the history record is monitored. When clicking the cancel button of the popup box, you can only return to the previous page by maintaining the allKeys array.

4.demo

The code is annotated, and more than 100 lines of code are written in a simple emasculated version of History, in order to understand how history works, it should be easy to understand.

(function(w){
  let History = {
    createBrowserHistory
  }

  function createBrowserHistory(){
    // key
    function createKey() {
      return Math.random().toString(36).substr(2.6);
    }

    // Get the address information
    function getDOMLocation(historyState = {}) {
      const { key, state } = historyState || {};
      const { pathname, search, hash } = window.location;

      return {pathname, search, hash, key};
    }
    // location Indicates the address
    let initialLocation = getDOMLocation()

    // Initialize allKeys
    let allKeys = [initialLocation.key]

    / / listen array
    let listener = []
    / / to monitor
    function listen(fn){
      listener.push(fn)

      checkDOMListeners()
    }

    // Only one function can be added to listen for changes to history entries
    let isListener = false
    function checkDOMListeners(){
      if(! isListener) { isListener =true
        window.addEventListener('popstate', handlePop)
      }
    }

    // Skip block. Because when cancel is clicked in the popup box, go is executed, and then handlePop is executed again, this time skipped
    let forceNextPop = false
    // Listen for historical entries to change
    function handlePop(event){
      let location = getDOMLocation(event.state)
      if (forceNextPop) {
        forceNextPop = false
      } else {
        / / the pop-up box
        let isComfirm = prompt && window.confirm(prompt(window.location)) && true

        if (isComfirm) {
          / / sure
          / / update the history
          Object.assign(history, {location, length: history.length})
        } else {
          / / cancel
          // Get the current history.key and the previous location.key comparison, and then jump back
          let toIndex = allKeys.indexOf(history.location.key)
          toIndex = toIndex === - 1 ? 0 : toIndex

          let fromIndex = allKeys.indexOf(location.key)
          fromIndex = fromIndex === - 1 ? 0 : fromIndex

          / / difference
          let delta = toIndex - fromIndex

          // If the difference is 0, no jump
          if (delta) {
            forceNextPop = true; go(delta); }}}}// intercepting functions
    let prompt = null
    function block(fn){
      prompt = fn
    }

    // push
    function push(href){
      let isComfirm = prompt && window.confirm(prompt(window.location)) && true

      if (isComfirm) {
        let key = createKey()
        // Update the allKeys array
        allKeys.push(key)
        // Update the history entry
        w.history.pushState({key}, null, href)
        
        // Get the latest location information
        let location = getDOMLocation({key})

        / / update the history
        Object.assign(history, {location, length: history.length})
      }
    }

    // go
    function go(n){
      w.history.go(n)
    }

    // goBack
    function goBack(){
      go(- 1);
    }

    let history = {
      length: w.history.length,
      listen,
      block,
      push,
      go,
      goBack,
      location: initialLocation
    }
    return history
  }

  w.History = History
})(window)
Copy the code

5. To summarize

Learning code must be handwritten, learning English must be open, learning must be active!