赞
踩
jQuery的点击事件中嵌套点击事件,当我们重复点击外层点击事件绑定的对象之后,再去点击内层的事件目标对象,我们就会遇到一个内层点击事件重复执行的问题。
(这个问题是在开发后台管理系统的时候遇到的,利用模态框增删改查之后进行确认时出现的问题,以下为一般探索过程,解决办法网上已经有很多,但是至于其真正产生的根本原因,有很多说得并不是很清楚,于是自己探索了一下。)
测试页面如下:
点击展开
重复点击5次之后再点击确认按钮
此时重复点击确认的话……
每点一下确认,内层的点击事件就会执行5次!!!
源码如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Document</title>
- </head>
- <style>
- div{
- width: 200px;
- height:100px;
- background-color: #cfcfcf;
- line-height: 100px;
- display: none;
- }
- </style>
- <body>
- <button id="btn1">展开</button>
- <div><button id="innerBtn">确认</button></div>
- <script src="../../jQuery/jQuery v3.3.1.min.js"></script>
- <script>
- let i = 1;
- $(function(){
- $("#btn1").click(function(){
- $("div").show();
- $("#innerBtn").click(function(){
- console.log(i++);
- })
- })
- })
- </script>
- </body>
- </html>
可以看到,重复点击5次展开/收起按钮之后再点击确认按钮是,控制台输出的结果为:1~5,也就是说内层的点击事件,在我点击确定的时候执行了5次。
网上的参考原因:发现每次点击外部的click事件后,内部的click事件都会绑定一次,因此会遍历很多次。
这里乍一看,好像是那么回事儿,细一想却就有点不清不楚了,为什么会是这个样子?
首先,每次点击外部click事件目标对象后,内部的click事件都会绑定一次是什么意思?
各种查资料,最后却要追究到jQuery中的click和DOM中的onclick的区别上来:
DOM中的onclick是js原生的处理事件;
jQuery中的click是其定义的一个方法,这个方法的本质是调用了DOM的onclick事件。
嗯……这和内部click事件多次绑定有什么关系吗?有,还真有:
如果我们将使用jQuery的代码改为原生的js,使用onclick来实现功能的话,就不存在以上的问题:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Document</title>
- </head>
- <style>
- div{
- width: 200px;
- height:100px;
- background-color: #cfcfcf;
- line-height: 100px;
- display: none;
- }
- </style>
- <body>
- <button id="btn1">展开</button>
- <div><button id="innerBtn">确认</button></div>
- <!-- <script src="../../jQuery/jQuery v3.3.1.min.js"></script> -->
- <script>
- let i = 1;
- // $(function(){
- // $("#btn1").click(function(){
- // $("div").show();
- // $("#innerBtn").click(function(){
- // console.log(i++);
- // })
- // })
- // })
- window.onload=function(){
- document.getElementById("btn1").onclick = function(){
- document.getElementsByTagName("div")[0].style.display = "block";
- document.getElementById("innerBtn").onclick = function(){
- console.log(i++);
- }
- }
- }
- </script>
- </body>
- </html>
无论之前点了多少次展开按钮,当我们点击确认时,内层的点击事件都只执行一次。
又是一番查资料不提,刚刚看到了事件监听,也就是addEventListener,突然想起了addEventListener 与 onclick的区别,其中有一条,大概的意思就是:addEventListener可以给对象绑定多个事件处理程序,而onclick只能绑定一个 事件处理程序。
也就是说:当我们使用事件监听(addEventListener)的方式给元素添加事件处理程序的时候,其实使用的是类似于push和append的方式,也就是增加事件处理程序,而当我们使用onclick的时候,其实是在给元素对象设置事件处理程序,也即是没有就加上,有就覆盖。
结合文章查看jQuery源代码不难发现,其实jQuery这货在绑定事件的时候,其实就是使用的addEventListener。
到这里,其实 “ 每次点击外部的click事件后,内部的click事件都会绑定一次,因此会遍历很多次。” 这句话,也就不那么难以理解了。
OK:
使用jQuery的click事件嵌套click,出现重复执行的原因,基本明朗了:
根本原因:
addEventListener重复绑定事件是增加 而不是覆盖!!
这就是:当我们点击外层click事件元素的时候,会执行其事件绑定的函数体,每点击一次就执行一次,而我们的外层点击事件的函数体内,又有绑定点击事件的语句时,相当于外层点击一次,内层就会给事件目标对象多加上一个点击事件。外层点击了多少次,内层事件目标对象就被绑定了多少个点击事件!!!所以才会在我们多次点击外层事件目标对象后再点击内层事件目标对象时,出现重复执行内层事件处理程序的情况。因为你本来就绑定了那么多次……
解决办法:
内层绑定事件之前,先解除事件目标对象上绑定的事件。
- let i = 1;
- $(function(){
- $("#btn1").click(function(){
- $("div").show();
- $("#innerBtn").off("click"); //解除绑定的点击事件
- $("#innerBtn").click(function(){
- console.log(i++);
- })
- })
- })
当然,解除事件绑定的方法还有很多,这里就不一一列出,下次有空在详细探究一番。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。