Javascript 基于历史的自定义后退按钮

Javascript 基于历史的自定义后退按钮,javascript,angularjs,history.js,html5-history,Javascript,Angularjs,History.js,Html5 History,在我的单页web应用程序中,我希望在一些页面上有一个后退按钮,可以将用户带回浏览器历史记录中的特定点:不一定是上一页 请注意,我不是说浏览器的后退按钮,它应该像往常一样工作 用例 例如,考虑Gmail Web应用程序。有一个文件夹视图,可能带有搜索过滤器或其他参数,然后是一个显示单个邮件的邮件视图。在messages视图中,有一个back按钮不会将您带到上一页:即使您在阅读多条邮件时单击了back按钮,在单击任何邮件之前,back按钮也会将您带回到最初来自的文件夹视图 在gmail的例子中,这是

在我的单页web应用程序中,我希望在一些页面上有一个后退按钮,可以将用户带回浏览器历史记录中的特定点:不一定是上一页

请注意,我不是说浏览器的后退按钮,它应该像往常一样工作

用例

例如,考虑Gmail Web应用程序。有一个文件夹视图,可能带有搜索过滤器或其他参数,然后是一个显示单个邮件的邮件视图。在messages视图中,有一个back按钮不会将您带到上一页:即使您在阅读多条邮件时单击了back按钮,在单击任何邮件之前,back按钮也会将您带回到最初来自的文件夹视图

在gmail的例子中,这是通过简单地编码URL末尾的前一个状态来实现的。例如,如果您通过搜索获得此消息,则它将是:

#search/stuff/<MESSAGE_ID>
然而,在我的应用程序中,有太多的状态无法在URL中对其进行编码。不是两个视图(文件夹+消息),而是三个视图,我们称它们为A、B和详细信息,A和B都有一系列可能的过滤器和选项编码在URL中,我希望在从B返回到A或从详细信息返回到B时保留它们。编码A的所有参数,B和详细信息页面的URL中的详细信息将使URL极其笨拙

实施 我认为这可以通过html5历史API轻松实现。然而,据我所知,history API不支持读取历史中的URL:您只能盲目地返回或前进

history.js提供对过去状态的访问,如相关问题中所述:

但是,我使用的angularjs与history.js不兼容,因为它直接与history api对话,而不是通过history.js,因此angular$location服务导致的转换状态不会显示在history.js的history对象中

似乎我需要做以下其中一项:

  • 让history.js与angular配合使用
  • 在我自己的代码中重新实现history.js功能的一个子集

我还考虑过使用document.referer查看历史记录中的上一个值,但这不起作用,因为在一个单页应用程序中导航时它不会被设置。

我从未使用过angular.js,但如果您希望某个应用程序能保证工作,那么您可能需要的是window.history.pushState。请仔细阅读,了解关于这个婴儿能做什么的详细信息。

回答我自己的问题,我选择了@MaxArt在评论中建议的更简单的解决方案

  • 为页面生成随机ID
    • 因为我使用angularjs,所以我在(“$routeChangeSuccess”)或(“$routeUpdate”)上执行$on
    • 如果没有angularjs,我想我会在PopState上做这件事
  • 在sessionStorage中存储从这个随机ID到我需要的所有URL信息(在我的例子中是搜索和路径)的映射
  • 在“我的应用”的概念层次结构中前进的传出链接中包含一个搜索参数from=当前页面的ID
  • 单击custom back按钮时,使用from seach参数在sessionStorage中查找我来自的状态
    • 如果找到,请返回该URL
    • 如果未找到(用户直接导航到此页面),请返回应用程序层次结构中上一个视图的默认URL
与构建过去URL历史的更一般方法相比,采用此方法的基本原理:

  • 如前所述,pushState API不提供对过去URL的访问
  • 将History.js集成到angularjs中,它确实提供了这些信息,这似乎并不简单
    • angularjs在内部使用历史API:需要将其更改为使用历史
  • 实现自定义代码以在sessionStorage中记录URL历史记录也并非易事。主要问题是,由于缺乏与浏览器历史记录的集成,似乎没有一种通用的方法来确定访问的页面是新页面还是通过返回浏览器历史记录中的一个或多个步骤来访问的页面。如果有人能提出解决方案(1),我很乐意得到纠正
  • 使用History.js或任何使用附加代码包装所有History.pushState的等效解决方案,几乎需要将页面上的所有链接包装在History.pushState中,否则URL更改不会显示在历史记录中

(1)

您可以添加自己的onpopstate或onhashchange来记录每个url更改,不管是谁做的。然后你有一个过去的URL列表,就像历史一样。此外,使用本机pushState,您可以将一个大状态与url关联起来,而无需对其进行编码,这与url的参数不同。@dandavis:我已经了解到了这一点,但这些信息存储在哪里?如果我不存储它,整个页面的重新加载将丢失历史记录。如果我将其存储在sessionStorage中,并且用户在两个选项卡中打开了我的页面,那么如何避免这两个选项卡的历史记录相互干扰?好的,我似乎可以简单地使用sessionStorage,因为快速测试确认sessionStorage未在选项卡之间共享。您不必对URL中的所有数据进行编码。只需使用与包含特定状态所需的所有内容的对象文本中的键匹配的ID即可。@dandavis:此外,onpopstate/onhashchange不会告诉我在历史中是返回还是前进……正如问题中所述,pushState API不提供对过去URL的访问。因此,我可以一步一步地返回,也可以多次返回,但我不能“在url与此模式匹配之前返回”true,但您只能使用pushState命令浏览器向堆栈中添加历史记录条目。您可以使用
history.go(-1)
导航“back”,无论您使用PushState添加了什么,它都应该可以工作。我理解,但我不想去
#search/stuff