仅捕获不是由锚点点击引起的 hashchange 事件
Posted
技术标签:
【中文标题】仅捕获不是由锚点点击引起的 hashchange 事件【英文标题】:Capture only hashchange events not resulting from anchor clicks 【发布时间】:2013-07-01 08:55:04 【问题描述】:我正在尝试使用 javascript 来模拟 CSS :target
伪类,以便捕获导致页面上的元素成为目标的所有事件。我已经确定了 3 个触发事件:
window.location.hash
在初始化时已经针对具有相同 ID 的元素
点击了指向该元素的锚点
hashchange
事件独立于上述事件触发(例如通过window.history
API)
场景 2 作为一个独特的案例很重要,因为我想调用 click
事件的 preventDefault
。此场景的简化代码如下:
$('body').on('click', 'a[href*=#]', function filterTarget(clickEvent)
$(this.hash).trigger('target', [clickEvent]);
);
在尝试实现方案 3 时出现问题:
$(window).on('hashchange', function filterTarget(hashChangeEvent)
$(this.hash).trigger('target', [hashChangeEvent]);
);
如果target
处理程序没有取消方案 2 的本机行为,则当本机行为导致生成的 hashchange
事件时,它将再次触发。如何过滤掉这些极端情况?
解决方案后编辑:
roasted 的答案是关键——处理命名空间的 hashchange 事件,然后根据 click 处理程序及其 preventDefault. I wrote up the full plugin here 内部处理的逻辑解除绑定并重新绑定处理程序。
【问题讨论】:
您能否举例说明用户如何使用您所描述的系统? @SamuelReid 我正在开发一个丰富的单页 Web 应用程序,重点关注渐进式增强:对于没有 Javascript 的用户代理在概念上可行的所有交互和导航都使用表单元素处理,并且(最常见的)链接——很多时候哈希用于导航或显示页面中的元素。但是当应用 Javascript 时,我经常想中断这些事件并替换本机行为。 @SamuelReid 举一个具体的例子:有一个类似“脚注查看器”的东西,可以显示大量引用。本机行为是简单地跳转到有问题的引文,但增强的行为打开了一个模态界面,以更好地与引文和源材料参考进行整体交互。我希望人们能够分享脚注的永久链接,但如果 JS 可用,我仍然希望尽可能使用“脚注查看器”。 所以你需要它,这样如果场景 2 不取消默认事件,场景 3 会运行? @SamuelReid no — 我是说点击导致的 hashchange 不应该触发另一个目标事件,因为从整体上来说,目标事件已经被捕获。 【参考方案1】:如果我理解它,您不希望在单击锚标记时触发 hashchange 事件。然后,您可以使用命名空间事件设置您的逻辑:
DEMO
$('body').on('click', 'a[href*=#]', function (clickEvent)
filterTarget(clickEvent,this);
$(window).off('hashchange.filter').on('hashchange.tmp', function ()
$(this).off('hashchange.tmp').on('hashchange.filter', filterTarget);
);
);
$(window).on('hashchange.filter', filterTarget);
function filterTarget(event,elem)
$(elem?elem.hash:window.location.hash).trigger('target', [event]);
//you could filter depending event.type
alert(event.type + '::'+ (elem?elem.hash:window.location.hash));
【讨论】:
这几乎正是我想要的——事件嵌套和链接让我很困惑,但现在我有时间解决它,我确信命名空间过滤是解决方案。我将扩展捕获的clickEvent
的preventDefault
以恢复hashchange
处理程序并在我对其进行排序后发布结果。
很抱歉没有早点授予赏金 - 我一直在等待,直到我有时间编写完成的脚本 - 但关键是你的解决方案非常完美,结果对我来说是奇迹。谢谢!
谢谢@Barney,很高兴为您提供帮助! :)【参考方案2】:
如果点击仍然使用片段设置哈希,只需丢弃哈希更改事件中的重复项:
onhashchange=function(e)
if(e.newURL == e.oldURL )return;
//do your normal hashchange event stuff below:
;
参考:https://developer.mozilla.org/en-US/docs/Web/API/window.onhashchange
无论是什么调用了更改,这都会修复级联问题。
【讨论】:
hashchange
隐含地处理了这个问题,因为e.newURL == e.oldURL
不会触发hashchange
的理论事件(没有变化)。在我确实想停止的实际hashchange
事件的上下文中(e.newURL != e.oldURL
),我需要知道根本原因是否是链接点击——这已经触发了target
事件。
【参考方案3】:
如果您要在其上调用 preventDefault,您似乎可以使用 mousedown 而不是单击。那么大概hashchange不会被触发。
【讨论】:
感谢您的建议。挑战在于不触发target
一次基于点击事件,然后再次基于hashchange
:实际上,我只希望target
触发hashchange
,如果hashchange
不是本身是 click
的结果(它已经触发了一次 target
事件)。以上是关于仅捕获不是由锚点点击引起的 hashchange 事件的主要内容,如果未能解决你的问题,请参考以下文章