如何使用浏览器历史记录API,在点击“后退”和“前进”按钮时调用函数?

3
假设我有一个页面: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在用户单击浏览器的返回按钮时隐藏第二步并显示第一步?


1
通常使用popstate事件来完成这个任务,但在使用history api时要考虑浏览器的支持情况。我倾向于使用库而不是自己构建,因为如果要兼容常见但不太现代的浏览器,这需要相当复杂的工作。 - Kevin B
1
使用一些巧妙的CSS技巧,您实际上可以完全不使用JavaScript来完成它。http://jsfiddle.net/Ps4XW/ :) 适用于现代浏览器。 - Yury Tarabanko
2个回答

0
以下代码是针对您在问题中提出的解决方案做出的响应。使用HTML5 History 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();
});

0
让我们把浏览器历史记录看作一个栈。每次点击链接或向前导航时,都会将项目推入堆栈中。每当要向后退时,浏览器就从堆栈中“弹出”一个项目。让我们称这些项目为“状态”。浏览器会保留有关每个状态的几个信息,例如URL、标题和(如果需要)“状态对象”。简而言之,在向前走时会将新状态推入堆栈,而在想要向后走时则会从末尾弹出最近的状态。
考虑到这一点,您想要实现的是手动将状态推入堆栈。通过这种方式,用户实际上并没有导航到任何地方——HTML5历史API使我们能够在不更改页面的情况下推送/弹出/替换浏览器历史记录堆栈中的状态。
在您的click事件侦听器中,您需要添加一些代码来将新状态添加到历史记录堆栈中。例如:window.history.pushState({},'Step 2','/step-2');

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

现在您必须考虑在用户浏览器中导航 back 时更改页面上这两个项目的可见性。这可以通过在每次状态更改时在 window 上触发的 popstate 事件来检测。查看我准备好的 this plunkr example。在 click 事件侦听器中,DOM 被更改(隐藏和显示项目),并推送了表示应在该历史状态中显示哪个步骤的整数的新历史状态。然后,在 popstate 事件中,用户正在向后导航,并在事件对象中,我们获得正在弹出的状态。我们知道我们应该向后走,因此如果被弹出的步骤是步骤 2,我们将要显示步骤 1。

我对HTML进行了一些小的更改,以便能够简洁地编写代码,并且这里有很多可扩展性——没有必要在JavaScript中硬编码步骤编号。

这样说清楚了吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接