如何在JavaScript中使用window.history?

时间:2015-07-21 00:22:28

标签: javascript html5 browser-history html5-history

我在Stack Overflow上发现了很多关于这个的问题,但是他们都对某些部分非常具体。我确实找到this问题,其答案提供了一些很好的参考,但他们并没有真正解释它是如何工作的,他们的例子几乎没有做任何事情。我想更多地了解它是如何一起工作的,我想使用vanilla JavaScript。

(此外,其他问题的许多答案都已有数年之久了。)

1 个答案:

答案 0 :(得分:29)

开始

首先,您可以删除window部分。只需history即可。但在我们开始讨论一切如何协同工作之前,我们需要知道我们可以使用什么。

重要事件

的window.onload

只要您的网页加载,就会触发此事件。有两种情况会触发此事件:

  1. 当您的网页从其他网页导航时。请注意,我写了网页,而不是网页网站。在同一站点上的页面之间移动将触发此事件。
  2. 在您的网页刷新后。
  3. window.onpopstate

    当您在设置的历史记录状态之间导航时,会触发此事件。您的浏览器会在正常浏览期间自动设置历史记录状态(为空),但导航到这些状态或从这些状态导航不会触发此事件。

    window.onunload

    每次卸载网页时都会触发此事件。有两种情况会触发此事件:

    1. 当您从网页导航到其他网页时。
    2. 在您的网页刷新之前。
    3. 重要对象

      历史界面包含五个函数(如下所述),两个只读对象(此处描述),有点像linked list。每个链接中包含的两个对象'历史对象是:

      • length - 这是当前浏览器窗口的历史状态数。它从1开始。
      • state - 这是一个几乎可以包含任何内容的JavaScript对象。默认情况下为null

      您可以分别致电history.lengthhistory.state来访问它们,但history.state只能用于获取当前历史记录状态。

      重要功能

      history.go(距离)

      此功能与按下浏览器中的后退或前进按钮的功能相同,增加的功能是能够准确指定您想要的距离。例如,history.go(3)与按下前进按钮三次具有相同的效果,而不会实际在开始和结束位置之间加载页面。负值同样会使您在历史中向后移动。 history.go(0)history.go()甚至history.go(NaN)与刷新页面具有相同的效果(这不会触发popstate事件)。如果你不能向前/向后移动到指定的范围,该功能将无效。

      history.back()

      此功能与浏览器中的后退按钮功能相同。它相当于history.go(-1)。如果它不能返回,该功能将什么都不做。

      history.forward()

      此功能与浏览器中的前进按钮功能相同。它相当于history.go(1)。如果无法继续,该功能将无效。

      history.replaceState(state,title [,location])

      此功能取代当前的历史状态。它需要三个参数,尽管最后一个是可选的。论点是:

      • 州 - 这是最重要的论点。您为此参数提供的对象将保存到history.state以供日后检索。这是一个深层复制,因此如果您以后修改原始对象,它将不会更改已保存的状态。您也可以将其设置为null,但如果您不打算使用它,则根本不会使用history
      • title - HTML标准建议用户界面中的浏览器可以使用传递给此参数的字符串,但目前没有浏览器对其进行任何操作。
      • location - 此参数允许您更改相对于当前页面的URL。它不能用于将URL更改为其他网站的URL,但可用于将URL更改为您的网站上的其他页面的URL。我会建议不要这样做,因为即使URL是另一个页面,页面实际上并没有重新加载。使用后退/前进将显示更改的网址,但不会更改网页,并会触发popstate而不是loadunload。更改其URL后刷新页面将加载由URL指定的页面而不是您之前使用的页面。此功能可用于在当前状态下提供指向页面的链接,但我建议仅更改查询字符串而不是完整URL。如果未使用此参数,则URL不会更改。

      history.pushState(state,title [,location])

      此函数与history.replaceState的作用相同,不同之处在于它将新状态置于当前状态之后,而不是替换当前状态。先前使用forward访问过的所有历史状态都将被丢弃,新状态将成为当前状态。

      组装PIECES

      历史记录界面非常有用,允许用户在浏览器中浏览动态生成的内容,而无需重新加载整个页面,但您需要注意用户可能会影响的所有可能的事情。历史状态。

      1. 首次导航到您的页面
        • 您的用户是否应该使用菜单/列表,某些特定的动态生成内容,或者某些随机动态生成的内容?
        • 如果没有history,甚至是JavaScript,您的页面是否会正常显示?
      2. 使用back/forward返回您的页面
        • 您的用户是否应该看到他们第一次看到的同一件事,或者他们是否应该看到他们的访问结果反映在内容中? (A"欢迎回来"消息对某些人来说可能是一个很好的接触,但对其他人来说是一种不必要的分心。)
      3. 刷新页面
        • 您是否应该获得新页面,返回起始页面或重新加载同一页面? (如果网址没有更改,您的用户可能不会期望最后一个。)
      4. 使用刷新页面中的back/forward
        • 您是否应该获得相对于刷新页面的新内容,或者重新加载以前保存的状态?
      5. 离开您的页面
        • 离开之前你需要保存吗?
      6. 通过deep link返回您的网页
        • 您是否有代码来识别和处理深层链接?
      7. 请注意,无法删除已保存的状态(上述pushState()的特定情况除外)。您只能将其替换为新内容。

        将它们全部放在一起

        由于这开始有点罗嗦,让我们用一些代码完成它。

        // This function is called when the page is first loaded, when the page is refreshed,
        // and when returning to the page from another page using back/forward.
        // Navigating to a different page with history.pushState and then going back
        // will not trigger this event as the page is not actually reloaded.
        window.onload = function() {
          // You can distinguish a page load from a reload by checking performance.navigation.type.
          if (window.performance && window.PerformanceNavigation) {
            let type = performance.navigation.type;
            if (type == PerformanceNavigation.TYPE_NAVIGATE) {
              // The page was loaded.
            } else if (type == PerformanceNavigation.TYPE_RELOAD) {
              // The page was reloaded.
            } else if (type == PerformanceNavigation.TYPE_BACK_FORWARD) {
              // The page was navigated to by going back or forward,
              // though *not* from a history state you have set.
            }
          }
        
          // Remember that the browser automatically sets the state to null on the
          // first visit, so if you check for this and find it to be null, you know
          // that the user hasn't been here yet.
          if (history.state == null) {
            // Do stuff on first load.
          } else {
            // Do stuff on refresh or on returning to this page from another page
            // using back/forward. You may want to make the window.onpopstate function
            // below a named function, and just call that function here.
          }
        
          // You can of course have code execute in all three cases. It would go here.
        
          // You may also wish to set the history state at this time. This could go in the
          // if..else statement above if you only want to replace the state in certain
          // circumstances. One reason for setting the state right away would be if the user
          // navigates to your page via a deep link.
          let state = ...; // There might not be much to set at this point since the page was
                           // just loaded, but if your page gets random content, or time-
                           // dependent content, you may want to save something here so it can
                           // be retrieved again later.
          let title = ...; // Since this isn't actually used by your browser yet, you can put
                           // anything you want here, though I would recommend setting it to
                           // null or to document.title for when browsers start actually doing
                           // something with it.
          let URL = ...;   // You probably don't want to change the URL just yet since the page
                           // has only just been loaded, in which case you shouldn't use this
                           // variable. One reason you might want to change the URL is if the
                           // user navigated to this page with a query string in the URL. After
                           // reading the query string, you can remove it by setting this
                           // variable to: location.origin + location.pathname
          history.replaceState(state, title, URL); // Since the page has just been loaded, you
                                                   // don't want to push a new state; you should
                                                   // just replace the current state.
        }
        
        // This function is called when navigating between states that you have set.
        // Since the purpose of `history` is to allow dynamic content changes without
        // reloading the page (ie contacting the server), the code in this function
        // should be fairly simple. Just things like replacing text content and images.
        window.onpopstate = function() {
          // Do things with history.state here.
        }
        
        // This function is called right before the page is refreshed, and right
        // before leaving the page (not counting history.replaceState). This is
        // your last chance to set the page's history state before leaving.
        window.onunload = function() {
          // Finalize the history state here.
        }
        

        请注意,我从未在任何地方拨打history.pushState。这是因为history.pushState不应该在这些函数中的任何地方调用。它应该由实际以某种方式更改页面的函数调用,您希望用户能够使用后退按钮进行撤消。

        总而言之,通用设置可能会像这样工作:

        • 检查if (history.state == null)功能中的window.onload
          • 如果为true,则使用新信息覆盖历史记录状态。
          • 如果为false,请使用历史记录状态恢复页面。
        • 当用户浏览页面时,请在发生重要事件时调用history.pushState,使用后退按钮可以撤消。
        • 如果/当用户使用其后退按钮并触发popstate事件时,请使用您设置的历史记录状态将页面恢复为先前的状态。
          • 如果/当用户使用他们的前进按钮时也这样做。
        • 使用unload事件在用户离开页面之前完成历史记录状态。