仅带有浏览器按钮的 Onhashchange

Posted

技术标签:

【中文标题】仅带有浏览器按钮的 Onhashchange【英文标题】:Onhashchange with browser buttons only 【发布时间】:2011-06-02 23:23:42 【问题描述】:

我遇到了这个问题(我正在使用 jQuery,但我不限于此):

我正在使用锚导航 (#id) 和 Ajax 请求的组合。为了让页面移动到位(使用锚导航)或获取信息(使用 Ajax),我使用了 onhashchange 事件。

编辑:我有一点错字。我忘了检查 mouseDown 标志是否为真并且 hashchange 事件被触发,所以我添加了 if 语句。

使用 jQuery,它看起来像这样:(当然,这段代码被包装在一个函数中,并在 DOM 加载时初始化,但对于这个问题并不重要)


$(window).bind('hashchange', function(e)  

为了确保只有支持 onhashchange 的浏览器能够读取我这样封装的代码:


if ('onhashchange' in window) 
  $(window).bind('hashchange', function(e)  

我的网络应用程序是这样制作的,我只希望在我点击浏览器中的后退/前进按钮时触发 onhashchange 事件。为此,我这样做:


if ('onhashchange' in window) 
  $(window).bind('mousedown hashchange', function(e)  

现在,如果我在视口内单击,我将触发 mousedown 事件。如果触发了 mousedown 事件,我知道我没有单击浏览器的后退/前进按钮,我可以使用如下标志停止 onhashchange 事件:


var mouseDown = false;

if ('onhashchange' in window) 
  $(window).bind('mousedown hashchange', function(e) 
    if (e.type === 'mousedown') 
      mouseDown = true;
    

    if (mouseDown && e.type === 'hashchange') 
      // if the mousedown event was triggered and when the haschange event triggers,
      // we need to stop the hashchange event and restore the mouseDown flag
      mouseDown = false;
      e.stopPropagation();          
    

    if (!mouseDown && e.type === 'hashchange') 
      // Do the onhashchange stuff here
    
  

这会导致 IE 出现问题,因为它会缝合您无法将鼠标事件绑定到窗口对象 (?)。 IE 永远不会“看到” mousedown 事件。

要解决这个 IE 问题,我可以使用“clientY”属性。此属性在 IE 中的所有事件调用中传递,并告诉您鼠标的坐标。如果 e.clientY 小于 0,则鼠标在视口之外,我会知道我通过单击浏览器的后退/前进按钮触发了 onhashchange。现在看起来像这样:


var mouseDown = false;

if ('onhashchange' in window) 
  $(window).bind('mousedown hashchange', function(e) 
    // IE: Use e.clientY to check if the mouse position was within the viewport (i.e. not a nagative value for Y)
    // !IE: Use e.type
    if (e.type === 'mousedown' || e.clientY > 0 ) 
      mouseDown = true;
    

    if (mouseDown && e.type === 'hashchange') 
      // if the mousedown event was triggered and when the haschange event triggers,
      // we need to stop the hashchange event and restore the mouseDown flag
      mouseDown = false;
      e.stopPropagation();          
     
    if (!mouseDown && e.type === 'hashchange') 
      // Do the onhashchange stuff here
    
  

这个解决方案非常有效,直到我不得不添加对使用键盘上的箭头进行导航的支持。现在,鼠标在屏幕上的位置无关紧要。只要 IE 窗口处于“活动状态”,在敲击键盘时就会触发监听键盘输入的 keydown 事件。这意味着 clientY 检查不再按预期工作。

问题:

据我所知,onhashchange 必须绑定到 window 对象。如果我希望能够通过侦听另一个事件来控制一个事件,则必须在同一个回调函数中处理所有事件。

我怎样才能让它工作?

【问题讨论】:

('onhashchange' in window) 如果尚未定义,则始终返回 false,如果已定义,则始终返回 true。这并不意味着浏览器实际上会在 hashchange 上执行代码 这类似于 window.onload ,除非实际分配了一个函数,否则它是未定义的,即使实际上所有浏览器都支持它。 是的,我故意省略了函数声明,因为我认为它与问题无关。 DOM 加载时调用绑定 hashchange 事件的函数。 【参考方案1】:

所以,简单地说-

“我如何区分后退/前进按钮按下与来自与 DOM 交互的导航”。

您可能需要一个标志,这样当您从代码更改 URL 的哈希部分时,您设置此标志,忽略 hashchange 事件,然后取消设置该标志。在这种情况下,该事件将被忽略(一种与您尝试执行的操作有关的反向解决方案)。您显然希望将其包装在一个函数中。

然而,一般来说,使用 hashchange 事件进行导航的应用程序通常会使用 hashchange 事件作为更改应用程序状态的一种手段。因此,入口点只有一个,无需区分事件是浏览器导航生成还是dom交互生成。我可能会建议改变你的方法。

我还要指出一个事实,即所有浏览器都可以支持历史记录(甚至是使用 iFrame hack 的 IE6 和 IE7)。看看jQuery history plugin

【讨论】:

该死,我知道可以用更短的方式来描述它;)这就是问题所在,哈希部分永远不会从代码中设置。它是从默认链接行为设置的,并利用浏览器历史记录通过浏览器按钮来回导航。改变方法不是一种选择。在我不得不实现 keyDown 事件之前,我的解决方案运行良好。此外,我没有提到这是针对 GT IE 7 的解决方案,因为我们可以与用户一起控制该部分。所以IE6和7不会有问题。 关于“改变应用程序的状态”。这个解决方案有点不同,因为它结合了动画锚导航和 ajax 调用。如果只是 ajax 调用,这将不是问题。 :) 无论如何,我会给出一个反向解决方案的想法,看看我是否能找到一个新的角度来解决这个问题。谢谢。 我不得不对代码其他部分的方法进行一些更改,只剩下这个函数的 hashchange 事件。它不是很漂亮,但现在可以使用。【参考方案2】:

实现此目的的参考库: http://benalman.com/projects/jquery-bbq-plugin/

我用过,效果很好

考虑把“!”在url中的“#”之后,以便google可以发现ajax页面 http://code.google.com/web/ajaxcrawling/docs/getting-started.html

【讨论】:

是的,我看过了。我并不是特别发现使用插件(或我没有为此编写的代码)。尤其是那些比我需要的功能更多的插件。在这种情况下,我正在构建一个封闭系统,因此谷歌永远不会看到这些页面。但无论如何感谢链接。这是一个很好的参考!

以上是关于仅带有浏览器按钮的 Onhashchange的主要内容,如果未能解决你的问题,请参考以下文章

捕获浏览器的前进后退事件 window.onhashchange 并区别于点击链接

JavaScript/jQuery - onhashchange 事件解决方法

VUE路由原理

SPA 单页面应用程序。

使用 AngularJS/Javascript 仅禁用浏览器后退按钮导航(不是应用程序中的链接)

前端路由模式hash和history