15

我正在使用 HTML5 History API 编写一个单页 javascript 应用程序。应用程序通过 Ajax 加载内容并在内部使用屏幕堆栈在前景屏幕上维护状态信息。

我想使用后退按钮启用导航,但我不想启用前进按钮。

一些快速的信息:

  • 用户应该只能返回,不能前进
  • 按浏览器后退按钮关闭当前页面屏幕用户打开并重新加载上一个
  • 项目仅针对最新版本的 Chrome,因此其他浏览器的实现并不重要
  • 我只使用本机 JavaScript 和 jQuery,我想在没有 History.js 的情况下这样做

当我加载一个新屏幕时,我运行以下行:

history.pushState(screenData, window.document.title, "#");

我通过 jQuery 绑定到 popstate 事件:

$(window).bind("popstate", function(event) {
    if (event.originalEvent.state != null) {
        // Logic that loads the previous screen using my screen stack
    }
}); 

我的应用程序的历史管理正在运行,但是当我返回时,前进按钮被启用。我需要弄清楚如何从事件中删除history数据popstate

我可以用 replaceState 做到这一点吗?我不知道该怎么做...

4

4 回答 4

11

坏部分

要真正禁用前进按钮,您必须能够删除浏览器历史记录,这是所有 javascript 实现都不允许的,因为它会允许站点删除整个历史记录,这永远不会符合用户的利益。

好部分

这有点棘手,但我想如果你想做自定义历史,它可能会起作用。您可以pushStatepopstate事件中使用,使您的实际页面成为最顶层的历史条目。我假设你处理历史的方式,你的窗口永远不会卸载。这使您可以自己跟踪用户历史记录:

var customHistory = [];

history.pushState(screenData, window.document.title, "#");像以前一样推送您加载的每个页面。只有您也将状态添加到自定义历史记录中:

history.pushState(screenData, window.document.title, "#");
customHistory.push({data: screenData, title: window.document.title, location: '#'});

现在,如果您有一个popstate事件,您只需弹出自定义历史并将其推送到最顶部的条目:

window.onpopstate = function(e) { 
  var lastEntry = customHistory.pop();
  history.pushState(lastEntry.data, lastEntry.title, lastEntry.location);
  // load the last entry
}

或者在 jQuery 中

$(window).on('popstate', function(e) {
  var lastEntry = customHistory.pop();
  history.pushState(lastEntry.data, lastEntry.title, lastEntry.location);
  // load the last entry
});
于 2012-07-18T20:43:35.270 回答
11

接受的答案解决了禁用前进按钮的问题,但创建了一个新的烦人问题“导航回的页面”被重复插入历史记录(如答案评论中所示)。

这是解决“禁用前进按钮”问题并避免“重复”后退按钮问题的方法。

//setup the popstate EventListener that reacts to browser history events
window.addEventListener("popstate",function(event){
     // In order to remove any "forward"-history (i.e. disable forward 
     // button), this popstate's event history state (having been navigated 
     // back to) must be insert _again_ as a new history state, thereby 
     // making it the new most forwad history state. 
     // This leaves the problem that to have this popstate event's history
     // state to become the new top, it would now be multiple in the history
     //
     // Effectively history would be:
     //  * [states before..] ->
     //  * [popstate's event.state] -> 
     //  * [*newly pushed _duplicate_ of popstate's event.state ]
     // 
     // To remove the annoyance/confusion for the user to have duplicate
     // history states, meaning it has to be clicked at least twice to go 
     // back, we pursue the strategy of marking the current history state
     // as "obsolete", as it has been inserted _again_ as to be the most
     // forward history entry. 
     // 
     // the popstate EventListener will hence have to distinguish 2 cases:
     //
     // case A) "popstate event is _not_ an obsolete duplicate"...
     if( typeof event.state == "object" 
         && event.state.obsolete !== true)
     {
         //...so we _firstly_ mark this state as to from now on "obsolete",
         // which can be done using the history API's replaceState method
         history.replaceState({"obsolete":true},"");
         // and _secondly_ push this state _one_more_time_ to the history
         // which will solve the OP's desired "disable forward button" issue
         history.pushState(event.state,"");
     }

     // case B: there is the other case that the user clicked "back" and
     // encounters one of the duplicate history event entries that are 
     // "obsolete" now.
     if( typeof event.state == "object" 
         && event.state.obsolete === true)
     {
         //...in which case we simply go "back" once more 
         history.back() 
         // by this resolving the issue/problem that the user would
         // be counter-intuively needing to click back multiple times.
         // > we skip over the obsolete duplicates, that have been the
         // the result of necessarily pushing a history state to "disable
         // forward navigation"
     }

},false);
于 2018-10-02T13:14:01.633 回答
5

只需使用以下 jquery 禁用前进按钮:

  $( document ).ready( function(){
    history.pushState(null,  document.title, location.href);        
   });
于 2018-11-14T06:35:37.553 回答
0

笔记:

  • 这段代码经过测试并且运行良好,没有显示任何问题,但是我会鼓励开发人员在将代码投入生产之前对其进行更多测试。
  • 如果在应用程序的任何地方使用HTML5 history.replaceState() ,下面的代码现在可能会起作用。

我创建了一个自定义函数来禁用前进按钮。

这是代码(它不适用于哈希路由策略):

  <script>
    (function() {
      // function called after the DOM has loaded
      disableForwardButton();
    })();

    function disableForwardButton() {
      var flag, loop = false;
      window.addEventListener('popstate', function(event) {
        if (flag) {
          if (history.state && history.state.hasOwnProperty('page')) {
            loop = true;
            history.go(-1);
          } else {
            loop = false;
            history.go(-1);
          }
        } else {
          history.pushState({
              page: true
            },
            null,
            null
          );
        }
        flag = loop ? true : !flag;
      });

      window.onclick = function(event) {
        flag = false;
      };
    }
  </script>

正如Redrif在已接受答案的评论中指出的那样,问题是您必须双击后退按钮才能导航回乏味且不切实际的页面。

代码说明:每次点击后退按钮时都需要创建一个额外的历史元素,这样你所在的当前页面就会指向新创建的历史页面。这样就没有页面可以前进,因为这pushState是最后一个状态(将其想象为数组中的最后一个元素),因此您的前进按钮将始终被禁用。

强制引入循环变量的原因是因为您可以有一个场景,您返回到某个页面并且pushState代码发生创建最后一个历史元素,而不是再次返回,您选择再次单击某个链接并再次返回上一页,现在创建了一个额外的历史元素。换句话说,你有这样的东西:

[第 1 页,第 2 页,第 2 页,第 2 页]

现在,一旦打开page2(索引 3 元素)并再次单击后退按钮,您将再次进入page2索引 1 元素,而您不希望这样。请记住,您可以拥有一个x page2元素数组,因此引入了循环 false 变量来解决该特定情况,page2无论数组中有多少page2元素,您都可以从它一直跳到第 1 页。

于 2018-06-23T13:01:42.070 回答