繁体   English   中英

聆听锚标记中所有可能包含子代的“ onClick”事件

[英]Listen to all “onClick” events from anchor tags that could possibly contain children

我正在尝试实现一个简单的(-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>

单独的JS文件

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

    if (
        tag.tagName.toUpperCase() === 'A' &&
        tag.href &&
        event.button == 0 &&
        tag.origin == document.location.origin
    ){
        event.preventDefault();
        console.log("default prevented")
    }
}

使用此代码,我仅检测到span事件,而不是<a>事件。 如何使用Vanilla JS检测锚点事件(如果可能)? 我也希望能够检测动态创建的锚点。

编辑1:更改了JS功能。 default prevented: SPAN打印控制台default prevented: 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.target元素中“遍历文档树”,直到找到一个定位标记。

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

 function findParentByTagName(element, tagName) { var parent = element; while (parent !== null && parent.tagName !== tagName.toUpperCase()) { parent = parent.parentNode; } return parent; } function handleAnchorClick(event) { event = event || window.event; if (findParentByTagName(event.target || event.srcElement, "A")) { event.preventDefault(); console.log("An anchor was clicked!"); } } document.documentElement.addEventListener("click", handleAnchorClick, false); 
 <p> <a href="#"> <span> <b> <i>Click me!</i> </b> </span> </a> </p> <p> <a href="#">Click me too!</a> </p> 

这是因为event.target将始终指向被单击的最深节点。

event.path本质上来说, 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突变事件,然后查询所有锚,过滤已附加事件侦听器的锚,将它们添加到列表中(以便可以在后续事件中过滤它们),最后附加事件侦听器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM