Javascript 倾听所有人的声音;onClick";来自可能包含子项的锚定标记的事件

Javascript 倾听所有人的声音;onClick";来自可能包含子项的锚定标记的事件,javascript,html,onclick,anchor,dom-events,Javascript,Html,Onclick,Anchor,Dom Events,我试图实现一个简单的(-ish)路由器作为练习。但是,我在检测锚点点击时遇到问题。理想情况下,我希望在URL更改时拦截事件(不使用哈希),但现在我只希望能够拦截任何锚单击事件 以下是我到目前为止所做的尝试: HTML <nav id="mainMenu"> <ul id="navlinks"> <li> <a href="/"> <span>HOME<

我试图实现一个简单的(-ish)路由器作为练习。但是,我在检测锚点点击时遇到问题。理想情况下,我希望在URL更改时拦截事件(不使用哈希),但现在我只希望能够拦截任何锚单击事件

以下是我到目前为止所做的尝试:

HTML

<nav id="mainMenu">
    <ul id="navlinks">
        <li>
            <a href="/">
                <span>HOME</span>
            </a>
        </li>
        <li>
            <a href="/posts">
                <span>POSTS</span>
            </a>
        </li>
    </ul>
</nav>
使用此代码,我只检测
span
事件,而不是
事件。使用vanilla JS(如果可能的话)我可以做些什么来检测锚点点击事件?我希望能够检测动态创建的锚以及

编辑1:更改了JS函数。控制台打印禁止的默认值:SPAN:

function intercept(event)
{
    console.log("triggered");
    var tag = event.target;

    //if (
    //    tag.tagName === 'A'
    //){
        event.preventDefault();
        console.log("default prevented: " + tag.tagName);
    //}
}

编辑2:锚定标记并不总是有子节点,并且可能的子节点可能不是
span
其原因是
事件。目标
将始终指向单击的最深节点

event.path
基本上是您所需要的,但是它还没有得到广泛的实现

下面是如何获取目标的所有父对象的数组,如event.path将生成:

function getPath(e) {
  return e.parentElement? [e].concat(getPath(e.parentElement)) : [e];
}
一旦具备该功能,就可以测试这些元素中是否有任何元素是锚点:

var thereIsAnAnchorInMyPath = getPath(event.target)
  .reduce(function(isAnchor, element) {
    return isAnchor || /^a$/i.test(element.tagName);
  }, false);
因此,你的例子是:

function intercept(event){
    console.log("triggered");
    var thereIsAnAnchorInMyPath = (event.path || getPath(event.target))
      .reduce(function(isAnchor, element) {
        return isAnchor || /^a$/i.test(element.tagName);
      }, false);

    if (thereIsAnAnchorInMyPath){
        event.preventDefault();
        console.log("default prevented")
    }
}
当然,只将事件侦听器附加到锚定会容易得多:

[].slice.call(querySelectorAll('a')).forEach(function(anchor) {
  anchor.addEventListener('click', intercept);
});
但是,如果(出于某种原因)在文档中插入新的锚,那么这将不起作用。在这种情况下,一旦将事件侦听器插入到文档中,您就需要将其附加到每个新的锚点

或者,您可以侦听DOM变异事件,然后查询所有锚点,筛选已附加事件侦听器的锚点,将它们添加到列表中(以便在后续事件中进行筛选),最后附加事件侦听器。

您需要做的就是“遍历文档树”从
event.target
元素,直到找到锚定标记

此解决方案的优点是它利用了事件委派,并且可以在页面生命周期的任何时候运行。
document.documentElement
属性是
标记,它在JavaScript开始执行时就存在

函数findParentByTagName(元素,标记名){
var父元素=元素;
while(parent!==null&&parent.tagName!==tagName.toUpperCase()){
parent=parent.parentNode;
}
返回父母;
}
函数句柄单击(事件){
event=event | | window.event;
if(findParentByTagName(event.target | | event.srcElement,“A”)){
event.preventDefault();
log(“锚被点击了!”);
}
}
document.documentElement.addEventListener(“单击”,手动单击,错误)


注释掉一些条件谓词,直到它按预期工作,然后重新修改条件。要检测导航尝试,您可以在正文上卸载之前侦听。@dandavis我的所有条件现在都消失了。它仍然只检测跨距点击。@dtanders这会让我阻止页面卸载吗?您如何绑定处理程序?这是一个很好的解决方案,但我将使用Greg Burghardt的答案,因为它更容易理解。我稍微修改了代码,以便访问检测到的锚标记(将
findParentByTargetName
的结果分配给局部变量)。我无法摆脱这样一种感觉,即这更像是一种解决办法。也许现在不可能。这是执行事件委派的基本方法。所有主要的JavaScript库或框架都从
事件开始。target
并在文档树上漫游,直到满足某个条件。我创建了一个事件委派库很少见的是,你可以插入到现有的代码中。它比这个解决方案更加健壮,但我不确定它是否适用于你的单页应用程序。
[].slice.call(querySelectorAll('a')).forEach(function(anchor) {
  anchor.addEventListener('click', intercept);
});