【问题标题】:Browser History Management浏览器历史管理
【发布时间】:2012-11-14 15:18:53
【问题描述】:

我正在尝试找到一个干净的解决方案,以最有效的方式处理浏览器历史记录。 (我用的是 GWT,不过这个问题确实比这更笼统。)

这是我的情况(我认为这很标准):

我有一个 Web 应用程序,它有几个不同的页面/地点/位置(无论你想怎么称呼它),我会根据浏览器历史记录的更改显示这些应用程序。除了通常是静态 HTML 页面的“主页”、“功能”、“联系人”等之外,还有一个“用户”部分,人们可以在其中登录他们的用户帐户和(我们称之为)“项目”部分,用户可以在其中处理他们的项目。

所以,现在我只使用名为 #Home#Features#Contact 等的本地链接,以及 #User#Project 以访问不同的页面。一切都很好,除了以下情况:

如果有人打开链接#Project,例如,该人会看到一个项目登录对话框。这个登录对话框有一个 cancel 按钮,我想通过从我的应用程序中调用浏览器的 back 按钮来实现它(很简单)。我想这样做的原因有两个:

  1. 您可以从应用程序中的多个不同位置以及您的书签访问此登录对话框,通过这种方法,我无需跟踪用户来自何处。
  2. 更重要的是:如果我确实记得用户来自哪里(例如 #Home)并将用户“前进”链接到该位置,我会得到以下效果:
    • 假设用户访问#Home,然后#Features,然后点击项目登录。
    • 如果用户点击 cancel 按钮,我将他“转发”到 #Features,然后点击浏览器的 back 按钮将返回登录对话框,然后再次返回 #Features,最后返回 #Home。不是你所期望的。
    • 相反,您希望立即返回 #Home,这正是我通过浏览器的返回功能实现 cancel 所得到的结果。

此时一切都很好,除非用户最初通过指向 #Project 的直接书签链接进入此登录对话框。因为那时,如果我只是简单地 cancel = back,用户就会从页面完全返回到他的浏览器的起始页面或他之前所在的任何地方。所以,在这种情况下,我确实需要将“转发”链接到 #Home

现在,我尝试了几种方法来解决这个问题,并提出了一些解决方案,但没有一个对我来说是非常理想的,但还是让我分享一下,也许可以激发一些创造力:

  • 首次打开页面时,获取历史令牌。如果是 #Project#User 或任何其他触发可取消对话框的内容,请将以下项目放入历史堆栈:#Home、#Project,其中最后一个是保存的初始令牌。然后,这允许我的 cancel 按钮正常工作......一次......但是,如果用户随后点击 back,他将再次获得登录对话框(因为原始历史令牌仍在历史堆栈中,我不知道如何清除它)。点击 cancel 然后会将他从页面上移除(不一致的行为)。
  • 我可以改为将 #+++#Home#Project 放到堆栈上,这样我就可以捕获一个back 点击,通过检测 #+++ 链接并简单地将 #Home 标记重新添加到堆。这将解决问题并且总体上工作得很好,除了我讨厌那些不让你在没有足够快地敲击后退按钮的情况下让你退出它们的网站......
  • 如果我能以某种方式跟踪历史堆栈的长度,就我的应用程序中的位置而言,最干净的解决方案是。一开始很容易:它上面有一个项目。但是,如果我得到如下的一系列位置:#Home#Features#Home?用户是否单击返回回到#Home,即浏览器中的历史现在长度为1,或者他是否单击了#Home em> 链接,即历史长度为 3?我检测这一点的想法是:
    • 定义,#Home#home 相同。
    • 让页面中的所有链接仅链接到大写版本的链接。
    • 每当您收到以 大写字母,立即在历史记录中添加两个项目, 第一个以小写字母开头,第二个也以大写字母开头。 IE。 #Home 变成 #Home#home#Home
    • 如果您收到以小写字母开头的历史更改,您就知道用户只是单击了 back 而不是链接,您只需单击 back 两次更多次让他真正回到上一页。
    • 现在您可以区分“后向”和“前向”链接,并在代码中维护准确的历史模型。
    • 但是,不幸的是,这有两个问题:第一,浏览器历史记录变得杂乱无章(不是很优雅),第二,如果用户单击 返回 kbd> 足够快,以至于您的应用没有时间对消息做出反应。

这似乎应该是一个非常普遍的问题,我希望你们中的一个人可以为我指出一个比我迄今为止的想法更有用的方向。

【问题讨论】:

  • 您是否考虑过使用像 angularjs 提供的客户端路由系统? angularjs.org它可以使用html5的push Stake来跟踪前后方向,并且会给你处理客户端直接到达路由的工具。
  • @thatjuan angularjs 似乎功能非常丰富,可能需要一段时间才能筛选出来。您是否足够了解它以用几句话总结与我的问题相关的部分?这将非常有帮助,谢谢。
  • 您看过活动和地点吗? developers.google.com/web-toolkit/doc/latest/…您有什么理由尝试发明自己的解决方案?
  • @AndreiVolgin 不幸的是,我认为活动和地点框架也没有解决这个特定问题的方法。它似乎没有办法告诉我“返回”电话是否会让我离开页面或是否安全,或者允许我在历史记录的当前位置插入一个“家”位置。除非,也许,我错过了什么?

标签: javascript html gwt back-button browser-history


【解决方案1】:

在您的用户可以访问#LOGIN 对话框之前,您的入口点类已执行。在本课程中,您可以记住最后已知的页面。在登录活动/演示者中,您可以添加一个浏览器历史事件处理程序,它检查最后一个已知位置是否为空。如果为 null,则将用户发送到 #HOME 页面。

您无需询问浏览器用户访问过您应用中的哪些位置。如果您愿意,您可以记住每个会话的全部历史记录:即 [#HOME, #LOGIN, #FEATURES, #HOME]。

【讨论】:

  • 如果用户使用浏览器的历史按钮随机导航,我如何确保我正确地记住历史?我所能做的就是保持我自己的历史,假设每一步都是“前进”的一步。因此,如果用户单击“主页”、“功能”、“返回”,那么我的历史记录现在将包含“主页”、“功能”、“主页”,无论浏览器的历史记录是否仅包含“主页”。不确定我是否了解如何使用它来决定如何处理对话框取消点击?
  • 在您最初的问题中,您描述了一个非常具体的问题:回到另一个网站。您只需要知道您自己的历史记录是否为空即可解决该问题。除此之外,让浏览器管理历史记录。
  • 不幸的是,这并没有为我提供这些信息。我永远无法判断用户是否回到“空”状态。假设我看到页面转换“Home”、“Features”、“Home”(从上方)。用户现在是否处于 BACK 让我离开页面的位置?还是回到“功能”? IE。他是否通过单击“功能”页面上的“返回”或链接或某处的另一个书签进入第二个“主页”?这是我需要解决的细节。
  • 如果您的历史记录以 [..., #HOME, #FEATURES] 结尾,并且下一个标记是 #HOME,您可以放心地假设它是向后移动。在这种情况下,从逻辑上讲,单击主页链接或按下后退按钮没有区别。
  • ???有很大的不同,因为如果用户单击#FEATURES 部分中的#HOME 链接并且我从我的代码中发出“返回”命令,他将安全地最终回到我的#FEATURES 部分页面,但如果用户通过单击浏览器中的“返回”按钮而不是链接返回#HOME,如果我从我的代码中发出另一个“返回”命令,我会将他踢出我的页面!而这种区别正是我的问题!
【解决方案2】:

你有一个Queue<String> historyQueue; 怎么样?

当页面第一次加载时,即onModuleLoad(),你初始化Queue。 当您捕获历史事件时,请检查它是返回还是新的历史令牌。 如果是后退,则将其从队列中弹出,如果是新的,则将其添加到队列中。这样,取消按钮只是一个token = historyQueue.pop() 并检查令牌是否为空。如果是,那么就像你说的back = cancel,那么就做适当的事情吧。

【讨论】:

  • 这将是一个很好的解决方案,除了两个问题: 不幸的是,我认为没有可靠的方法来检测页面更改是“前进”还是“后退”更改。而且,更糟糕的是,如果这是可能的,那么您可能无法正确处理许多浏览器在历史记录中随机跳转的能力。
【解决方案3】:

window.history 有一个length 属性,它将显示当前选项卡的历史记录中有多少条目。不幸的是,它不可过滤(所以没有办法说window.history.localURLs.length)。

如果您几乎完全在客户端执行此操作(即部分更新、很少的整页加载、使用哈希或history.(push|pop)State API),那么您可能需要考虑将客户端路由框架合并到您的应用程序,以避免重新发明轮子。

【讨论】:

  • 不错!这正是我希望能帮助我解决这个问题的简单细节。现在我需要做的就是在页面首次加载时存储history.length,然后让我的“返回”功能检查是否有要返回的内容,如果没有,将其变成“主页”链接!甜的!谢谢!我很惊讶 GWT 没有公开这一点。它是完全跨浏览器的吗?我马上试试。
  • 啊!它几乎有效!除了它返回的历史长度不仅仅是我仍然可以点击“返回”的次数,还包括我可以点击“前进”的次数!有了它,它就不再起作用了......是否有一个只返回“返回”计数的等价物?
  • @Markus - 不幸的是,没有。
  • 我找到了办法!我只是将用户“转发”链接到一个虚拟链接以清除历史的转发部分,然后从我的程序中点击“返回”,这样可以确保列表中只有一个“转发”链接。现在,它是可靠的!完美的!谢谢!
  • 不幸的是,这种方法并不能在所有浏览器中可靠地工作,这就是为什么我不得不不接受这个答案以希望找到一个可行的解决方案。
猜你喜欢
  • 2010-11-01
  • 2012-05-22
  • 2011-05-11
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 2015-10-10
  • 2015-04-03
  • 1970-01-01
相关资源
最近更新 更多