jQuery中stopPropagation导致动态元素点击事件不触发如何解决
问题场景
- 基础DOM结构:class为
mainCon的主容器嵌套class为wrapper的子容器,wrapper初始内置1个按钮 - 初始按钮交互:点击后隐藏自身,同时向
wrapper内追加一个p元素 - 预期效果:点击
mainCon区域(不含wrapper内部范围)时隐藏主容器;点击wrapper内部任意元素时,不触发主容器的隐藏逻辑,原方案计划通过stopPropagation()阻止事件冒泡实现该效果 - 实际异常:按钮追加p元素的逻辑可正常执行,但点击动态追加的p元素时,绑定的点击事件完全不触发。已知两个诱因:① p是动态新增元素,初始直接绑定的事件无法生效;② 冒泡拦截逻辑错误,拦截了正常的事件传递。
问题复现代码
JavaScript
$('.mainCon').on('click', function() { $(this).css('display', 'none') }) $('.wrapper button').on('click', function() { $(this).css('display', 'none') $('.wrapper').append('<p>Click me now</p>') }) // 以下写法均无法正常生效 $('.wrapper p').on('click', function() { console.log('clicked') }) $('.mainCon .wrapper').click(function(e) { e.stopPropagation(); }); /* $('body').on('click', '.mainCon > *', function(e){ e.stopPropagation(); }); */
CSS
.mainCon { display: flex; width: 100%; height: 200px; background-color: gold; } .wrapper { display: flex; width: 70%; height: 70%; margin: auto; background-color: pink; } .wrapper button { height: 30%; margin: auto; } .wrapper p { text-decoration: underline; cursor: pointer; margin: auto; }
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="mainCon"> <div class="wrapper"> <button>Click me 1st</button> </div> </div>
失效原因
- 直接给
.wrapper p绑定事件失效:jQuery普通事件绑定仅对绑定执行时已经存在的DOM元素生效,后续动态追加的p元素不会被挂载事件。 - 直接给
.mainCon .wrapper绑定stopPropagation失效:一是该绑定同样只针对初始存在的wrapper本身,无法覆盖后续动态新增到wrapper内的元素;二是直接在wrapper层阻止所有冒泡,会拦截子元素的事件向上传递,导致委托在更高层级的子元素事件无法触发。 - 注释中的body委托写法失效:选择器
.mainCon > *仅匹配mainCon的直接子元素(即wrapper本身),不会匹配wrapper内部的button、p等后代元素,点击内部p元素时不会触发该拦截逻辑,事件会直接冒泡到mainCon触发隐藏。
修复方案
所有涉及动态元素的逻辑统一使用事件委托,绑定到页面初始加载时就存在的祖先元素上,同时调整冒泡拦截的覆盖范围,避免过度拦截:
// 主容器点击隐藏逻辑 $('.mainCon').on('click', function() { $(this).css('display', 'none') }) // 委托到mainCon,拦截wrapper及内部所有元素的点击冒泡,覆盖动态新增元素 $('.mainCon').on('click', '.wrapper, .wrapper *', function(e) { e.stopPropagation(); }) // 初始按钮点击逻辑,使用事件委托统一写法 $('.wrapper').on('click', 'button', function() { $(this).css('display', 'none') $('.wrapper').append('<p>Click me now</p>') }) // 动态p元素的点击逻辑,委托到初始存在的wrapper上 $('.wrapper').on('click', 'p', function() { console.log('clicked') })
修复逻辑说明:
- 事件委托依赖事件冒泡机制,只要把事件绑定到页面加载时就存在的祖先元素,后续新增的子元素触发事件时,冒泡到祖先元素就会匹配对应选择器执行逻辑,解决动态元素无法绑定事件的问题。
- 冒泡拦截的选择器覆盖wrapper本身和其所有后代元素,不管是初始的button还是后续追加的p,点击时都会阻止事件继续冒泡到mainCon,不会误触发主容器隐藏。
- p元素的点击事件委托在wrapper层,事件冒泡到wrapper时就会被捕获触发,不会被错误拦截。
内容的提问来源于stack exchange,提问作者seriously
相关产品推荐
相关产品推荐

