如何获取卡片中单击的父元素的ID?

时间:2018-12-08 14:21:55

标签: javascript html

我正在尝试使某些“卡片”彼此相邻显示,并且当单击卡片时,我想要获得卡片的ID。但是,除非单击卡div的边框,否则我的函数将在单击时获得未定义的子元素的ID,而不是父卡的ID。我如何确定它具体获得了卡的ID?

这是HTML:

<div id="parentCard" onclick="getID(event)">
  <div id="child1">I'm a child</div>
  <div id="text">
    <p>Text 1</p>
    <p>Text 2</p>
    <p>Text 3</p>
  </div>
</div>

Javascript:

function getID(event){
  console.log(event.target.id);
}

3 个答案:

答案 0 :(得分:3)

获取事件的目标元素(单击的元素)。

这里,我使用destructuring从目标中获取idtagNameparentNode属性。

如果单击的元素是card div元素,请记录ID,否则记录父元素的ID。

注意:这假设卡片的嵌套HTML不会比您示例中的嵌套嵌套深,或者parentNode不会应用于正确的父元素。

const parent = document.getElementById('parentCard');
parent.addEventListener('click', handleClick, false);

function handleClick(e) {
  const { id, tagName, parentNode } = e.target;
  console.log(tagName === 'DIV' ? id : parentNode.id);
}
<div id="parentCard">
  <div id="child1">I'm a child</div>
  <div id="text">
    <p>Text 1</p>
    <p>Text 2</p>
    <p>Text 3</p>
  </div>
</div>

答案 1 :(得分:2)

尝试使用Event.currentTarget,其中

  

标识事件的当前目标,因为事件遍历DOM。它始终是指事件处理程序已附加到的元素,而不是event.target,它标识发生事件的元素。

function getID(event){
  console.log(event.currentTarget.id);
}
<div id="parentCard" onclick="getID(event)">
  <div id="child1">I'm a child</div>
  <div id="text">
    <p>Text 1</p>
    <p>Text 2</p>
    <p>Text 3</p>
  </div>
</div>

答案 2 :(得分:2)

每次用户单击页面上的某处时,用户代理都会确定单击了哪个“非复合”元素,并触发以“ that ”元素为事件的“ click”事件类型的事件目标。

此处的“非复合”元素表示不包含后代元素的元素(例如,可能具有后代 nodes ,例如文本)。

由于您的卡片通常是复合元素-包含其他元素(可能又包含其他元素),因此无法保证点击事件target属于这些元素。

用户代理是一台机器,无法为您考虑,也无法知道用户“单击卡”。如果卡片中包含按钮,链接或图像,则用户代理所要做的就是通过事件的target属性告知您用户单击了哪个按钮-需要确定一个事实,即从您的角度来看,有人点击了卡片。

至少有两种方法可以确定所述事实:

  1. 找出哪个卡元素是或包含被点击的元素:

    function get_card(element) {
        for(; element; element = element.parentElement) {
            if(is_card(element)) return element;
        }
    }
    

    遍历祖先列表,您如何知道某个元素是一张牌?就文档对象模型而言,它只是一个div元素,具有一个onclick属性和一个ID。您的文档中可能有div个元素,它们具有已定义的idonclick属性,而不是卡片。

    向元素添加类是对它进行分类的自然方法:

    <div class="card">
        <!-- descendant elements -->
    </div>
    

    通过上述内容,我们决定并假设每个卡片元素的类名列表中都应包含“卡片”。现在,您可以编写is_card函数(用于get_card),如下所示:

    function is_card(element) {
        return element.classList.contains("card");
    }
    

    使用程序中的get_card(element)功能,您现在可以可靠地回答问题“哪张卡包含element?”。结合使用window对象上的单个事件侦听器,您现在可以知道用户单击了哪张卡:

    addEventListener("click", function(ev) {
        var card = get_card(ev.target);
        if(card) {
            /// A card was clicked, do something about it.
        }
    }
    

    如您所见,您甚至不需要在每张卡上添加侦听器,只需将一个添加到一个容器元素(如上面的情况,即window),就可以使用此解决方案

    现在,这是所谓的线性时间算法的一种情况-您的卡(“后代”元素依次包含其他后代元素)越“深”,定位该卡所需的平均时间就越长后代元素。但是,如果允许我在此处通用,则无需担心“点击”处理和现代JavaScript运行时的性能。

  2. 对card的孩子使用[到目前为止的实验] CSS4和pointer-events: none规则。假设每个卡都包含“ card”类,则可以指定没有任何后代元素启用指针事件-这些绝不会触发“ click”事件,而card元素将改为:

    .card > * {
        pointer-events: none;
    }
    

    pointer-events的支持仍处于试验阶段,但我知道最近的Google Chrome和Firefox都支持它。不过,您在这里要特别小心-例如,您是否准备禁用某些卡片元素的交互性?如果那里有通常是交互式的表单元素怎么办?您需要自己评估这些要求。

有第三个解决方案,但我认为它至少不及第一个解决方案。为了完整起见,在每张卡片上分配事件侦听器可能很浪费,尤其是在每页上有很多卡片的情况下。但是,无论如何,如果您像您自己那样将“ click”侦听器附加到卡上,则事件类型“ click”的侦听器将添加到该元素,该属性可以通过ev.currentTarget属性使用!意味着无论哪个后代元素触发“ click”事件,该事件都会通过其capturebubbling阶段到达card元素,并且currentTarget属性值将始终引用侦听器添加到的元素-在这种情况下是card元素。当然,此解决方案意味着将侦听器附加到每张卡上。