点击事件触发两次,但仅设置一次

时间:2019-10-23 09:34:56

标签: javascript events ecmascript-6

我有一个奇怪的问题,即两次单击事件被触发,我不知道为什么会发生。

JS Fiddle单击名称之一,以便触发切换按钮,如果您在label元素之外单击,则不会发生,实际上只会触发一次。

我将事件附加到所有带有'testit'类的元素上,当我记录元素时,我得到一个长度为1的节点列表,当我记录了foreach循环正在运行多少次时,它就会运行一次。

enter image description here

如果我删除Javascript,则不会附加任何事件。

    // SELECTER DEN FEATURED JOKE
    $sql = " SELECT t1.cat_id,
            t1.cat_name,
            t1.cat_parent,
            t1.cat_type
            FROM categories t1
            ORDER BY t1.cat_parent,
            t1.cat_name";
    $stmt = $dbCon->prepare($sql);
    $stmt->execute();
    $count = $stmt->rowCount();
    if ($count > 0) {
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $orders = [];
        foreach($rows as $row){
            $cat_parent = $row['cat_parent'];
            if($cat_parent == 0){
                $orders[$row['cat_id']]['parent'] = [
                    'cat_id' => $row['cat_id'],
                    'cat_name' => $row['cat_name'],
                    'cat_parent' => $row['cat_parent'],
                    'cat_type' => $row['cat_type']
                ];
                continue;
            }

            if ($cat_parent != 0) {
                $orders[$cat_parent][] = [
                    'cat_id' => $row['cat_id'],
                    'cat_name' => $row['cat_name'],
                    'cat_parent' => $row['cat_parent'],
                    'cat_type' => $row['cat_type']
                ];
                continue;
            }
        }

        $filter_html  = '<form id="filter__form" class="filter__form testit">';
        $filter_html .= '<ul class="filter__ul main">';
        foreach($orders as $order){
            $cat_id     = escape($order['parent']['cat_id']);
            $para       = escape($order['parent']['cat_id']);
            $cat_name   = escape($order['parent']['cat_name']);
            $cat_parent = escape($order['parent']['cat_parent']);
            $cat_type   = escape($order['parent']['cat_type']);

            $filter_html .= '<label class="filter__label parent" for="filter_'.$cat_id.'">';
            $filter_html .= '<p class="noselect">'.$cat_name.'</p>';
            $filter_html .= '<input id="filter_'.$cat_id.'" type="checkbox" value="'.$cat_id.'" name="cat['.$cat_id.']" class="cat_parent" data-show="cat_subs_'.$cat_id.'">';
            $filter_html .= '<i></i>';
            $filter_html .= '</label>';
        }
        $filter_html .= '<input type="hidden" name="CSRFToken" value="'.$_SESSION['CSRFToken'].'">';
        $filter_html .= '</ul>';
        $filter_html .= '</form>';
    }
?>

<div class="filter__head">
    <h3 class="">
        Filter - Dashboard
    </h3>
</div>

<?php
    echo $filter_html;
?>

JavaScript

    window.addEventListener("load", function (e) {


        var testit = document.querySelectorAll('.testit');

        console.log(testit);

        testit.forEach(function(e){
            console.log('TESTIT');
            e.addEventListener('click', function(){
                alert('Hello world');
            });
        });
   });

因此,该事件运行两次,这在控制台中得到确认,或者在事件触发时通过发出警报来确认,该节点对象的长度为1,如果我对其进行控制台操作(如果删除Javascript也不会确认),则该对象也得到确认。附件,这是怎么回事?

如果我在echo $filter_html的底部做一​​个带有一类testit的按钮,然后单击该按钮,它将仅触发一次,有什么区别,如何在一个特定元素中触发两次,并在一次触发一次,有什么区别?另一个,是同一事件吗?。

如果我附加了mouseup事件,则所有事件仅触发一次。

如果我注释掉标签元素,它将不会触发两次?为什么会这样?

CSS

.filter__head h3{
    padding: 15px;
    background-color: #eee;
    text-align: start;
    color: #4a4a4a;
}
.filter__form{
    max-height: 70vh;
    height: 600px;
    overflow: auto;
}
.filter__form .filter__ul .filter__label{
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    border-bottom: 1px solid rgba(0,0,0,0.06);
    padding: 15px 20px;
    cursor: pointer;
}
.filter__form .filter__ul .filter__label:last-child {
  border-bottom: 1px solid #BBB;
}
.filter__form .filter__ul .filter__label > input {
  display: none;
}
.filter__form .filter__ul .filter__label i {
  display: inline-block;
  float: right;
  padding: 2px;
  width: 40px;
  height: 20px;
  border-radius: 13px;
  vertical-align: middle;
  transition: .25s .09s;
  position: relative;
  background: #d8d9db;
  box-sizing: initial;
}
.filter__form .filter__ul .filter__label i:after {
  content: " ";
  display: block;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  position: absolute;
  left: 2px;
  transition: .25s;
}
.filter__form .filter__ul .filter__label > input:checked + i {
  background: #4bd865;
}
.filter__form .filter__ul .filter__label > input:checked + i:after {
  -webkit-transform: translateX(20px);
          transform: translateX(20px);
}
.filter__form .filter__ul .filter__label:hover {
  cursor: pointer;
}

2 个答案:

答案 0 :(得分:1)

通过单击包装输入和其他元素的label元素,触发表单上的第二个click事件。标签元素触发关联输入元素上的click事件。 MDN says

  

在单击label并将其与表单控件关联时,也会为关联的控件引发点击事件。

防止单击标签的默认操作不是解决方案,因为这会阻止关联复选框的状态更改。一种解决方法是,在复选框的状态更改时,附加input事件而不是click来执行所需的操作。

如果有更多的输入要以表格的形式进行监听,则与使用这种类型的事件委托时一样,情况将变得更加复杂。在这种情况下,您必须检查事件是否确实是由您希望响应点击的元素触发的。

答案 1 :(得分:0)

发生的事情是,您将事件附加到表单本身,这是具有类testit的唯一元素。

尝试将事件侦听器添加到输入中,然后使用 event object 标识每个输入:

var inputs = document.querySelectorAll('.cat_parent'); 
  inputs.forEach(function(input) { 
     input.addEventListener('click', function(event) { // you need to pass the event
       alert(event.currentTarget.id); // Now in the event object you have just the one that was clicked
      });
});