如何使用浏览器历史api在返回时调用函数&单击前进按钮

How to use the browser history api to invoke a function when back & forward buttons are clicked?

本文关键字:amp 单击 按钮 函数 调用 历史 浏览器 何使用 api 返回      更新时间:2023-09-26

假设我有一个页面:http://www.example.com/foo.htm

我想放置一个按钮,显示页面的一部分并隐藏另一部分,例如:

HTML-

<p class="stepOne">Hi, I'm step one. <a id="doit" href="#">Go to Step 2</a></p>
<p class="stepTwo">And I'm step two</p>

JS-

$('#doit').on('click', function(){
    $('.stepOne').hide();
    $('.stepTwo').show();
});

我的问题是:在用户单击"转到第二步"链接后,当用户单击浏览器的后退按钮时,我如何使用HTML历史api来隐藏第二步并显示第一步?

让我们把浏览器的历史记录看作一个堆栈。每次单击链接或向前导航时,都会将项目推到堆栈上。每当你想后退时,浏览器就会从堆栈中"弹出"一个项目。让我们将这些项中的每一项称为"状态"。浏览器会保存一些关于每个状态的信息,如URL、标题和"状态对象"(如果需要(。总之,当你前进时,新的状态会被推到堆栈中,而当你想后退时,最近的状态会从末尾弹出。

考虑到这一点,您想要实现的是手动将状态推送到堆栈上。通过这种方式,用户实际上并不在任何地方导航——HTML5历史API使我们能够在不更改页面的情况下推送/弹出/替换浏览器历史堆栈中的状态。

click事件侦听器中,您需要添加一些代码来向历史堆栈添加新状态。类似于:window.history.pushState({}, 'Step 2', '/step-2');

这将向历史堆栈添加一个新状态,并且您的URL将更改为/step-2。现在,当您单击后退按钮时,它将从堆栈中pop此状态,并返回到以前的状态。这两种状态都是相同的页面和DOM。

现在,当用户在浏览器中导航back时,您必须考虑更改页面上这两个项目的可见性。这可以通过每次状态更改时在window上触发的popstate事件来检测。看看我举的这个庞克的例子。在点击事件监听器中,DOM被更改(隐藏和显示项目(,并且一个新的历史状态被推送到堆栈上,其中一个整数表示应该在该历史状态中显示哪个步骤。然后,在popstate事件中,用户向后导航,在事件对象中,我们得到了弹出的状态。我们知道我们应该向后走,所以如果弹出的步骤是步骤2,我们将显示步骤1。

我对html做了一些小的修改,以便能够简洁地编写代码,这里有很大的模块化空间——不需要在javascript中硬编码步骤号。

这有道理吗?

下面的代码用于解决您在问题中提出的问题。使用HTML5历史Api,我们像这样扩展您的示例代码(注释描述了添加到代码中的A、B、C三个部分(

// Part A: For the initial "step 1" we create a history state object
var historyStateObjectStep1 = {"step":"one"};
// which we tell the browser to use to represent the current state/step in
// history. Since the browser had an idea about the "now"-state in history 
// already, which is now "replaced" this is done via history.replaceState
history.replaceState(historyStateObjectStep1,"");
// Part B: To react to history events like back-/forward-button pressed, 
// we have to setup an EventListener for the "history"-popstate event. 
window.addEventListener("popstate",function(event){
      // the history state objects we have setup via replaceState/pushState
      // before are provided via the event objects property event.state
      var historyStateObject = event.state;
      // if state object is "object" and as setup has an attribute "step" 
      // with value "one"
      if(typeof historyStateObject == "object" 
         && historyStateObject.step === "one" )
      {
          // then it means that the user used the browsers "back" button 
          // and since we are now at history state "stepOne" we show it
          $('.stepOne').show();
          // and hide stepTwo
          $('.stepTwo').hide();
      } 
      // in else case that the historyStateObject is an object and has an
      // attribute step set to the value "two" then...
      else if(typeof historyStateObject == "object" 
         && historyStateObject.step === "two" )
      {
          //...the user has used the browser buttons (forward/back) to reach
          // the state "stepTwo", hence we show it and 
          $('.stepTwo').show();
          // hide stepOne
          $('.stepOne').hide();
      }
},false);

$('#doit').on('click', function(){
    // PART C: Upon clicking the "doit"-button (to go to step two), we 
    // create an history state object for step 2 
    var historyStateObjectStep2 = {"step":"two"};
    // which we then insert intto the browser history, or in other words 
    // "push" the newly created historyStateObejectStep2 to the history, via
    // the function history.pushState
    history.pushState(historyStateObjectStep2,"");

    $('.stepOne').hide();
    $('.stepTwo').show();
});