javascript - 如何在JavaScript中使用window.history?

标签 javascript html browser-history html5-history

我在Stack Overflow上发现了很多与此有关的问题,但是它们对某些部分都非常具体。我确实找到了this问题,其答案提供了一些不错的引用,但实际上并没有解释其全部工作原理,因此他们的示例几乎无济于事。我想了解更多有关它们如何协同工作的信息,并且我想使用 Vanilla JavaScript。

(此外,许多其他问题的答案已有很长的历史了。)

最佳答案

入门

首先,您可以删除window部分。只是history可以正常工作。但是在我们研究所有事物如何协同工作之前,我们需要知道可以使用什么。

重要的事件

window.onload

每当您的网页加载时,就会触发此事件。有两种情况将触发此事件:

  • 当您的网页从另一个网页导航到时。请注意,我写的是网页,而不是网站。在同一站点的页面之间移动将触发此事件。
  • 刷新页面后。

  • window.onpopstate

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

    window.onunload

    只要您的网页被卸载,就会触发此事件。有两种情况将触发此事件:
  • 当您从网页导航到另一个网页时。
  • 在刷新网页之前。

  • 重要对象

    历史记录接口(interface)包含五个函数(如下所述),两个只读对象(在此描述),并且有点像linked list。历史记录对象的每个“链接”中包含的两个对象是:
  • length-这是当前浏览器窗口的历史状态数。它从1开始。
  • 状态-这是一个JavaScript对象,几乎可以包含任何内容。默认为null

  • 您可以通过分别调用history.lengthhistory.state来访问它们,尽管history.state仅可用于获取当前历史记录状态。

    重要功能

    history.go(距离)

    此功能与按浏览器中的“后退”或“前进”按钮具有相同的作用,其附加功能是可以精确指定要行驶的距离。例如,history.go(3)具有与按下前进按钮3次相同的效果,而无需实际在起始位置和结束位置之间加载页面。负值也会使您在历史记录中倒退。 history.go(0)history.go()甚至history.go(NaN)与刷新页面具有相同的效果(这不会触发popstate事件)。如果无法向前或向后移动到指定范围,则该功能将无效。

    history.back()

    此功能与浏览器中的“后退”按钮具有相同的功能。它等效于history.go(-1)。如果无法返回,则该功能将不执行任何操作。

    history.forward()

    此功能与浏览器中的前进按钮具有相同的功能。它等效于history.go(1)。如果无法前进,则该功能将不执行任何操作。

    history.replaceState(状态,标题[,位置])

    此功能替换当前历史记录状态。它需要三个参数,尽管最后一个是可选的。参数为:
  • state-这是最重要的参数。您为此参数指定的对象将保存到history.state中,以供以后检索。这是一个深拷贝,因此如果您以后修改原始对象,它将不会更改保存状态。您也可以将其设置为null,但是如果您不打算使用它,那么使用history根本没有多大意义。
  • title-HTML标准建议传递给此参数的字符串可由浏览器在用户界面中使用,但当前没有浏览器对其进行任何操作。
  • location-此参数允许您更改相对于当前页面的URL。它不能用于将URL更改为另一个网站的URL,但可以用来将URL更改为您网站上另一个页面的URL。但我建议您这样做,因为即使URL是另一个页面,该页面实际上也不会被重新加载。使用后退/前进将显示更改的URL,但不会更改页面,并且将触发popstate而不是loadunload。更改其URL后刷新页面将加载该URL指定的页面,而不是您先前所在的页面。可以使用此功能在当前状态下提供指向您页面的链接,但是我建议您仅更改查询字符串,而不要更改完整URL。如果不使用此参数,URL将不会更改。

  • history.pushState(状态,标题[,位置])

    该函数与history.replaceState相同,不同之处在于它将新状态放在当前状态之后而不是替换当前状态。先前可能已使用forward访问的所有历史记录状态都将被丢弃,新状态变为当前状态。

    组装零件

    历史记录界面非常有用,它允许您的用户在其浏览器中浏览动态生成的内容而不必重新加载整个页面,但是您需要注意用户可能执行的所有可能影响历史记录状态的操作。
  • 第一次导航到您的页面
  • 是否应该为您的用户提供菜单/列表,某些特定的动态生成的内容或某些随机的动态生成的内容?
  • 如果没有history甚至没有JavaScript,您的页面能否正确显示?
  • 使用back/forward返回您的页面
  • 您的用户应该看到的还是他们第一次看到的东西,还是应该看到内容中反射(reflect)出的访问结果? (“欢迎回来”消息对某些人可能是一种很好的触动,但对其他人却是不必要的干扰。)
  • 刷新页面
  • 您应该获得一个新页面,返回到起始页面还是重新加载同一页面? (如果URL不变,您的用户可能不会期望最后一个。)
  • 从刷新的页面使用back/forward
  • 是应该获取有关刷新页面的新内容,还是重新加载以前保存的状态?
  • 离开您的页面
  • 您离开之前需要保存任何东西吗?
  • 通过deep link返回您的页面
  • 您是否具有识别和处理深层链接的代码?

  • 请注意,无法删除已保存的状态(除了上面提到的pushState()的特定情况之外)。您只能将其替换为新内容。

    全部放在一起

    由于开始有点罗word,让我们用一些代码结束它。
    // 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事件可在用户离开页面之前确定历史记录状态。
  • 关于javascript - 如何在JavaScript中使用window.history?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31528432/

    相关文章:

    javascript - Google map Javascript API/街景 FOV

    javascript - HTML 中的结束标记

    javascript - Promise.all() - 如何在不返回 undefined 或 value 的情况下 resolve()

    javascript - asp.net使用jquery和javascript来确定与按钮匹配的文本框ID的中间部分

    python - 使用 Python 从解析的 HTML 中提取文本

    html - WavPack用于html音频播放

    javascript - Jquery:TypeError: $(...)._TMS 不是函数

    javascript - 使用 JavaScript 操作 session 历史记录

    javascript - 使用react-router的历史记录,有没有办法在不使用push()或replace()的情况下返回到之前渲染的特定页面?

    javascript - history.go ('url' ) 问题