【问题标题】:Event delegation on click of an option, doesn't work on cloned element单击选项时的事件委托,不适用于克隆元素
【发布时间】:2021-06-13 16:52:53
【问题描述】:

我之前的问题(已关闭)-> Jquery - Cloning a div which includes input unordered lists. How to get the dropdown to work in the cloned row?

我被提到了这个答案:-> Event binding on dynamically created elements?

我一直在尝试使用哪个静态祖先,克隆版本不会注册任何点击。

例如,在我的第一个版本中,我使用了 .on。从下拉列表中单击一个选项来运行一个函数,该函数将分配一个选定的类,这将取消隐藏下一个下拉列表。

$(".option").on("click", unhideoption2);

但是对于我添加的每个父/静态选择器,它仍然没有注册对克隆版本的任何点击

例如

$(".optionlist").on("click", ".option", unhideoption2);

$(".cselect").on("click", ".option", unhideoption2);

$(".row1").on("click", ".option", unhideoption2);

我应该将事件委托添加到被克隆的行而不是单个输入吗?虽然当我也尝试这样做时,它仍然没有注册克隆行上的点击。

$(".rows").on("click",'.clonerow', clonerow);

事件委托哪里出了问题?

https://jsfiddle.net/pfhnr9uk/4/

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rows">
<div class="row1">
  <div class="cselect options1">
    <input type="text" disabled placeholder="Select n1">
    <ul class="optionlist">
      <li class="option option1">Business</li>
      <li class="option option2">Hair</li>
    </ul>
  </div>
<div class="cselect options2 hide">
    <input type="text" disabled placeholder="new test">
    <ul class="optionlist">
      <li class="option option1">test</li>
      <li class="option option2">option 2</li>
    </ul>
  </div>
</div>
<div class="row2">

  <div class="cselect options3">
    <input type="text" disabled placeholder="Select n2">
    <ul class="optionlist">
      <li class="option">Something</li>
      <li class="option">Else</li>
    </ul>
  </div>
</div>
<div class="clonerow">
click me
</div>
</div>

CSS

* {
  margin: 0;
  padding: 0;
}

/* ugly reset */

.cselect {
  position: relative;
}

.cselect input {
  background: #fff;
}

.cselect ul {
  display: none;
  position: absolute;
  z-index: 999;
  left: 0;
  top: 1.2rem;
  margin: 0;
  width: 100%;
  background: #fff;
  border: 1px solid #d6d6d6;
}

.cselect li {
  padding: 10px 5%;
  list-style: none;
}

.cselect li:hover {
  background: rgba(41, 128, 185, 0.2);
}

.hide{
  display:none;
}

JS

$(function() { // DOM ready


  $(".cselect").each(function() {

    var $input = $(this).find("input");
    var $dropDown = $(this).find("ul");

    $(this).on("click", function() {
      $dropDown.stop().slideToggle();
    });

    $dropDown.on("click", "li", function() {
      $input.val($(this).text());
    });

  });

});

var newnewid = 0;
var $cloneplayerclause = jQuery(".row1").clone(true);

function clonerow(){
  
  newnewid++;
  var $sectionClone = $cloneplayerclause.attr("id", newnewid).clone(true);
  $('.rows').append($sectionClone);
  
  
}

function unhideoption2(){
 $(".option").removeClass('selected');
 $(this).addClass('selected');
 if($('.option1').hasClass('selected')){
 $('.options2').removeClass('hide');
 }
 }

$(".option").on("click", unhideoption2);
$(".clonerow").on("click", clonerow);

【问题讨论】:

    标签: javascript jquery clone event-delegation


    【解决方案1】:

    事件处理程序不会被克隆,但您可以在.rows 框上创建事件处理程序,如下所示:

    $(function() { // DOM ready
      const rows = $(".rows").on("click", function(e) {
        if (e.target.tagName == "INPUT") {
          const input = rows.find(e.target);
          input.parent().find("ul").stop().slideToggle();
        } else if (e.target.classList.contains("option")) {
          const li = e.target;
          const ul = li.parentNode;
          const divSelect = ul.parentNode;
          const row = divSelect.parentNode;
          const input = divSelect.querySelector("input");
          if (!divSelect.dataset.hidden)
            row.dataset.hidden = li.dataset.hidden;
    
          input.value = li.textContent;
          $(input).click();
          for(let i = 0; i < ul.children.length; i++)
          {
            ul.children[i].classList.toggle("selected", ul.children[i] === li);
          }
          const hiddenRows = row.querySelectorAll(".cselect[data-hidden]");
          for(let i = 0; i < hiddenRows.length; i++)
          {
            hiddenRows[i].classList.toggle("hide", !row.dataset.hidden || row.dataset.hidden != hiddenRows[i].dataset.hidden);
          }
        }
      });
    });
    var newnewid = 0;
    var $cloneplayerclause = jQuery(".row1").clone(true);
    
    function clonerow() {
    
      newnewid++;
      var $sectionClone = $cloneplayerclause.attr("id", newnewid).clone(true);
      $('.rows').append($sectionClone);
    
    
    }
    
    $(".clonerow").on("click", clonerow);
    * {
      margin: 0;
      padding: 0;
    }
    
    
    /* ugly reset */
    
    .cselect {
      position: relative;
    }
    
    .cselect input {
      background: #fff;
    }
    
    .cselect ul {
      display: none;
      position: absolute;
      z-index: 999;
      left: 0;
      top: 1.2rem;
      margin: 0;
      width: 100%;
      background: #fff;
      border: 1px solid #d6d6d6;
    }
    
    .cselect li {
      padding: 10px 5%;
      list-style: none;
    }
    
    .cselect li:hover {
      background: rgba(41, 128, 185, 0.2);
    }
    
    .hide {
      display: none;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="rows">
      <div class="row1">
        <div class="cselect options1">
          <input type="text" disabled placeholder="Select n1">
          <ul>
            <li class="option option1" data-hidden="1">Business</li>
            <li class="option option2">Hair</li>
            <li class="option option3" data-hidden="3">Face</li>
          </ul>
        </div>
        <div class="cselect options2 hide" data-hidden="1">
          <input type="text" disabled placeholder="new test">
          <ul>
            <li class="option option1">test</li>
            <li class="option option2">option 2</li>
          </ul>
        </div>
        <div class="cselect options2 hide" data-hidden="3">
          <input type="text" disabled placeholder="face type">
          <ul>
            <li class="option option1">type 1</li>
            <li class="option option2">type 2</li>
          </ul>
        </div>
      </div>
      <div class="row2">
    
        <div class="cselect options3">
          <input type="text" disabled placeholder="Select n2">
          <ul>
            <li class="option">Something</li>
            <li class="option">Else</li>
          </ul>
        </div>
      </div>
      <div class="clonerow">
        click me
      </div>
    </div>

    【讨论】:

    • 您好 Vanowm 感谢您的回复!我已经从答案中做出了一个js小提琴,但它似乎不允许你选择一个选项。它可以正确克隆,但例如我无法单击“业务”。这是 jsfiddle -> jsfiddle.net/un2p8ox3
    • 固定隐藏行
    • 嗨 Vanown,我会给你接受的答案。只有一个问题..在我的原始代码中,选择第1个选项'业务'时出现第二个下拉目。看来这对您不起作用,我看到您取出了我用于它的功能。你知道是什么导致它不起作用吗?我希望第二个下拉列表仅在下拉列表 1 上选择第一个选项后出现 - 我面临的问题是克隆版本没有响应选择的第一个选项,因此第二个下拉列表从未出现在克隆上排。谢谢
    • 它在我的版本中工作......除非我不明白它应该如何工作......一旦在第一个下拉列表中选择“业务”,它就会取消隐藏隐藏字段。同样的事情发生在克隆的行中
    • 我创建了这个最新的 jsfiddle,它在原始行中工作,但在克隆版本中它不会取消隐藏隐藏字段 -> jsfiddle.net/un2p8ox3/1
    【解决方案2】:

    如何做到这一点的基本示例。

    关键在这里:

    function clonerow(){
    
            let cloneplayerclause = $(".row1").clone(false);
    
          let sectionClone = $(cloneplayerclause).attr("class", "rowx").find(".cselect").each(function() {
    
            var $input = $(this).find("input");
            var $dropDown = $(this).find("ul");
    
            $(this).on("click", function() {
              $dropDown.stop().slideToggle();
            });
    
            $dropDown.on("click", "li", function() {
              $input.val($(this).text());
            });
    
          });
          
          $('.rows').append(sectionClone);
          
          
        }
    

    完整示例,试试示例:

    $(function(){
    
    
      $(".cselect").each(function(){
    
        var $input = $(this).find("input");
        var $dropDown = $(this).find("ul");
    
        $(this).on("click", function() {
          $dropDown.stop().slideToggle();
        });
    
        $dropDown.on("click", "li", function() {
          $input.val($(this).text());
        });
    
      });
      
      let cloneplayerclause = $(".row1").clone(false);
      
      window.cloneplayerclause = cloneplayerclause;
    
    });
    
    
    function clonerow(){
    
        let sectionClone = $("<div class='rowx' />")
        
        $(cloneplayerclause).clone(true, true).find(".cselect").each(function(){
    
        var $input = $(this).find("input");
        var $dropDown = $(this).find("ul");
    
        $(this).on("click", function() {
          $dropDown.stop().slideToggle();
        });
    
        $dropDown.on("click", "li", function() {
          $input.val($(this).text());
        });
        
        $(sectionClone).append(this);
    
      });
      
      $('.rows').append(sectionClone);
      
      $(".option").on("click", unhideoption2);
      
    }
    
    function unhideoption2(){
     $(".option").removeClass('selected');
     $(this).addClass('selected');
     if($(this).parent().parent().parent().find('.options1 ul li').hasClass("selected")){
     $(this).parent().parent().parent().find('.options2').removeClass('hide');
     }
     }
    
    $(".option").on("click", unhideoption2);
    $(".clonerow").on("click", clonerow);
    * {
      margin: 0;
      padding: 0;
    }
    
    /* ugly reset */
    
    .cselect {
      position: relative;
    }
    
    .cselect input {
      background: #fff;
    }
    
    .cselect ul {
      display: none;
      position: absolute;
      z-index: 999;
      left: 0;
      top: 1.2rem;
      margin: 0;
      width: 100%;
      background: #fff;
      border: 1px solid #d6d6d6;
    }
    
    .cselect li {
      padding: 10px 5%;
      list-style: none;
    }
    
    .cselect li:hover {
      background: rgba(41, 128, 185, 0.2);
    }
    
    .hide{
      display:none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <html>
    
        <head>
        
            <script type="text/javascript" src="jquery-3.5.1.min.js"></script>
        
        </head>
        
        <body>
        
            <div class="rows">
            <div class="row1">
              <div class="cselect options1">
                <input type="text" disabled placeholder="Select n1">
                <ul>
                  <li class="option option1">Business</li>
                  <li class="option option2">Hair</li>
                </ul>
              </div>
            <div class="cselect options2 hide">
                <input type="text" disabled placeholder="new test">
                <ul>
                  <li class="option option1">test</li>
                  <li class="option option2">option 2</li>
                </ul>
              </div>
            </div>
            <div class="row2">
    
              <div class="cselect options3">
                <input type="text" disabled placeholder="Select n2">
                <ul>
                  <li class="option">Something</li>
                  <li class="option">Else</li>
                </ul>
              </div>
            </div>
            <div class="clonerow">
            click me
            </div>
            </div>
    
            <script type="text/javascript" src="index.js"></script>
    
        </body>
    
    </html>

    我在函数 unhideoption2 中使选项部分更加动态

    if($(this).parent().parent().parent().find('.options1 ul li').hasClass("selected")){
     $(this).parent().parent().parent().find('.options2').removeClass('hide');
     }
    

    【讨论】:

    • 谢谢你的作品!有没有办法让克隆版本看起来像原版?我的意思是,第二个下拉列表仅在选择下拉列表 1 中的第一个选项时显示,但是如果我选择一个选项并且第二个下拉列表出现然后克隆,则克隆版本在它应该隐藏时也具有第二个下拉列表。这是因为 'let cloneplayerclause = $(".row1").clone(false);'发生在函数内部和点击之后而不是事先被克隆?感谢您的帮助
    • unhideoption2这个函数的关键在这里,我大概调试了30分钟,现在明白了。
    • 我需要在该功能中进行哪些更改?
    • 您需要更改选择器,因为如果您例如单击“头发”选项,则不会取消隐藏元素,我在 unhideoption2 上使用此更改编辑我的帖子,更改是 -> @ 987654326@
    • 我击败了最后一部分,使选项更加动态if($(this).parent().parent().parent().find('.options1 ul li').hasClass("selected")){ $(this).parent().parent().parent().find('.options2').removeClass('hide'); }
    猜你喜欢
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多