我正在尝试使用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
事件时,它将再次被触发。如何过滤掉这些边缘案例?
解析后编辑:
baked的答案掌握了关键——处理一个名称空间的hashchange事件,然后根据click处理程序内部处理的逻辑及其preventDefault来解除绑定和重新绑定处理程序。我在这里写了完整的插件。
如果我理解的话,你不希望在点击锚标记时触发hashchange事件。然后,您可以使用名称空间事件设置逻辑:
演示
$('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));
}
如果点击是用片段设置哈希,只需在哈希更改事件中丢弃重复项:
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
这修复了级联问题,无论是什么调用了更改。
如果要调用preventDefault,似乎可以使用mousedown而不是单击。那么可能不会触发hashchange。