为.details ul li设置事件委托时删除操作失效,原因是什么?
事件委托绑定在li上失效的原因分析
问题描述
当把事件委托绑定在.details ul上时,点击p标签的删除操作可正常执行;但改为绑定在.details ul li上时,删除操作失效。为什么p标签的点击事件无法触发绑定在li上的委托逻辑?
相关代码
JavaScript
$(function() { $('.btn').click(function() { if ($('.message').val()) { var li = $('<li></li>'); li.html($('.message').val() + '<p>删除</p>'); $('ul').prepend(li); li.slideDown(); $('.message').val(""); } }) // 绑定在ul上有效,换成$('.details ul li').on(...)则失效 $('.details ul').on('click', 'p', function() { $(this).parent().remove(); }) })
CSS
* { padding: 0; margin: 0; } li { list-style: none; } .main { margin: 50px auto; overflow: hidden; border: 1px solid black; padding: 10px; width: 560px; } .message { margin-left: 5px; margin-right: 5px; width: 437px; height: 156px; border: 1px solid #ccc; outline: none; resize: none; } .info { margin-top: 140px; } .btn { margin-top: 140px; } .info, .message, .btn { float: left; } .details { margin-left: 70px; margin-top: 170px; width: 437px; } .details ul li { display: none; border-bottom: 1px dotted #ccc; } .details ul li p { float: right; color: red; }
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="main"> <div class="info">微博发布</div> <textarea name="" class="message" cols="30" rows="10"></textarea> <input type="button" value="发布" class="btn"> <div class="details"> <ul> <li>hello <p>delete</p> </li> </ul> </div> </div>
原因分析
核心问题出在事件委托的绑定逻辑和元素的动态性上:
- 事件委托的本质是把事件绑定在一个静态存在的父元素上,利用事件冒泡机制捕获子元素的事件。
- 当你用
$('.details ul li').on('click', 'p', ...)绑定委托时,jQuery只会给页面初始化时已经存在的li元素添加委托逻辑。而你通过发布按钮新增的li是后续动态创建的,这些新li并没有被包含在初始选择器的集合里,所以它们无法监听内部p标签的点击事件。 - 虽然p标签的点击事件确实会冒泡到父级li,但如果这个li是动态新增的,它本身从来没有被绑定过委托处理逻辑,自然不会触发删除操作。
- 而绑定在
.details ul上时,ul是页面加载就存在的静态元素,所有动态添加的li里的p点击事件都会冒泡到ul,ul上的委托逻辑能正确捕获到事件并执行删除。
另外补充:页面默认的那个li是display:none状态,即便能点击到它的p标签,绑定在它上面的委托是生效的,但动态生成的li没有这个委托,所以会出现“只有默认li能删(但看不到),新增的删不了”的现象。
解决方法
继续使用静态父元素作为委托载体(推荐,符合事件委托的最佳实践):
保持原代码中绑定在.details ul上的逻辑即可。动态创建li时绑定委托:
如果一定要绑定在li上,需要在每次生成新li的时候,给它单独绑定委托:$('.btn').click(function() { if ($('.message').val()) { var li = $('<li></li>'); li.html($('.message').val() + '<p>删除</p>'); // 给新创建的li绑定委托 li.on('click', 'p', function() { $(this).parent().remove(); }); $('ul').prepend(li); li.slideDown(); $('.message').val(""); } })
内容的提问来源于stack exchange,提问作者kittates
相关产品推荐
相关产品推荐

