click点击事件嵌套中的重复执行问题的根本原因

探讨jQuery点击事件嵌套导致重复执行的原因及解决方法。通过对比原生JS与jQuery的事件绑定方式,揭示了addEventListener与onclick的区别。

问题描述:

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++);
          })
     })
})

当然,解除事件绑定的方法还有很多,这里就不一一列出,下次有空在详细探究一番。

 

<think>好的,我现在需要解决用户的问题:如何在Adobe Animate中将鼠标单击事件传递到嵌套的影片剪辑中。首先,我得理解用户的具体需求。用户可能遇到了点击嵌套的影片剪辑时,事件没有正确触发的情况,或者希望父级和子级都能响应点击事件。接下来,我需要回忆Animate中事件处理的基本机制,尤其是涉及嵌套元件时的传播方式。 根据之前的引用内容,用户提到影片剪辑可以嵌套,并且可以使用ActionScript进行控制[^1][^2]。因此,解决方案可能涉及ActionScript 3.0的事件处理。在AS3中,事件流分为三个阶段:捕获、目标和冒泡。默认情况下,事件监听器在目标阶段和冒泡阶段触发。如果子级影片剪辑没有阻止事件冒泡,父级可能也会接收到事件。 接下来,我需要考虑如何确保点击子级影片剪辑时,事件能传递到父级。可能需要检查子级是否阻止了事件的传播,比如调用了stopPropagation()方法。如果子级没有阻止,父级只需添加事件监听即可。如果子级需要单独处理事件,同时让父级也能响应,可能需要使用冒泡阶段或者在子级的事件处理函数中手动触发父级的事件。 另外,用户可能希望点击父级区域时,即使点击在子级上,也能触发父级的事件。这时候可能需要设置子级的mouseEnabled或mouseChildren属性为false,以防止子级拦截事件。或者,在父级上使用addEventListener并设置useCapture参数为true,在捕获阶段处理事件,这样可以先于子级处理。 还需要考虑代码的结构,确保父级和子级实例都有正确的实例名称,以便在代码中引用。例如,父级影片剪辑命名为parentMc,内部的子级命名为childMc,然后在父级的代码中添加事件监听,或者在子级中分派自定义事件,由父级监听。 可能遇到的问题包括事件被多个对象处理导致重复触发,或者事件没有按预期冒泡。这时需要检查事件流阶段和是否调用了stopPropagation。此外,如果子级影片剪辑本身没有添加事件监听,父级可能无法捕获到事件,除非在捕获阶段处理。 最后,总结几种可能的解决方法:1. 使用事件冒泡,不在子级阻止事件传播;2. 在捕获阶段处理事件;3. 在子级中手动触发父级事件;4. 调整鼠标交互属性。需要根据具体情况选择合适的方法,并提供代码示例帮助用户理解。</think>在Adobe Animate中实现鼠标单击事件向嵌套影片剪辑的传递,需要通过ActionScript 3.0的事件处理机制来控制。以下是具体实现方法: ### 一、基础事件传递原理 ActionScript 3.0事件流包含三个阶段: 1. **捕获阶段**:从舞台向目标对象传递 2. **目标阶段**:到达具体触发对象 3. **冒泡阶段**:从目标对象反向传递回舞台 默认情况下,嵌套影片剪辑会阻断事件冒泡。例如点击子级影片剪辑时,父级无法直接收到事件[^1][^2]。 ### 二、核心解决方法 #### 方法1:启用冒泡事件 ```actionscript // 在子级影片剪辑中设置 childMC.addEventListener(MouseEvent.CLICK, onClickChild); function onClickChild(e:MouseEvent):void { e.stopPropagation(); // 移除这句允许事件冒泡 } ``` #### 方法2:强制穿透事件 ```actionscript // 在父级容器设置监听(捕获阶段处理) parentMC.addEventListener(MouseEvent.CLICK, onClickParent, true); function onClickParent(e:MouseEvent):void { trace("捕获阶段接收到事件"); } ``` #### 方法3:手动传递事件 ```actionscript // 在子级影片剪辑中 function onClickChild(e:MouseEvent):void { dispatchEvent(new MouseEvent(MouseEvent.CLICK, true)); // 主动向上冒泡 } ``` ### 三、高级控制技巧 1. **设置鼠标交互属性** ```actionscript childMC.mouseEnabled = false; // 禁用子级自身响应 childMC.mouseChildren = false; // 禁用子级后代响应 ``` 2. **事件穿透层级** ```actionscript parentMC.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { if(e.target == parentMC) { // 确保事件最终目标 // 执行父级操作 } }); ``` ### 四、完整实现示例 ```actionscript // 父级影片剪辑代码 this.addEventListener(MouseEvent.CLICK, onParentClick, true); function onParentClick(e:MouseEvent):void { trace("父级捕获事件: " + e.target.name); if(e.target is ChildMC) { // 判断点击对象类型 trace("检测到子级点击"); } } // 子级影片剪辑代码 this.addEventListener(MouseEvent.CLICK, onChildClick); function onChildClick(e:MouseEvent):void { trace("子级响应点击"); // e.stopImmediatePropagation(); // 阻止事件传递 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值