为什么这会导致最大的调用堆栈错误?

时间:2017-01-04 07:56:38

标签: javascript jquery callstack

此代码块触发了最大调用堆栈错误:

$(".resume_box").click(function () {
   $("#resume_upload").trigger("click");
});

这是它引用的HTML:

<div class="resume_box">
   <div class="file_instructions"> Please use .pdf format</div>
   <div class="button_plate">Choose a file</div>
   <input id = "resume_upload" type = "file" name = "resume" style = "display: none" />
</div>

我已经检查过,JS文件或具有相同名称,类或ID的HTML文件中没有其他内容。这是堆栈的样子:

trigger @   jquery.min.js:4
(anonymous) @   jquery.min.js:4
each    @   jquery.min.js:2
each    @   jquery.min.js:2
trigger @   jquery.min.js:4
(anonymous) @   script.js:70
dispatch    @   jquery.min.js:3
r.handle    @   jquery.min.js:3
trigger @   jquery.min.js:4
(anonymous) @   jquery.min.js:4
each    @   jquery.min.js:2
each    @   jquery.min.js:2
trigger @   jquery.min.js:4
(anonymous) @   script.js:70

重复最后8行,直到超出堆栈大小。

5 个答案:

答案 0 :(得分:5)

问题是因为您在父级的单击处理程序中触发了对子元素的单击。然后,此事件将DOM向上传播回父级,从而触发对子级的单击,该子级传播到父级,触发传播的子级...因此无限递归和堆栈错误。

要解决此问题,最好同时将单击处理程序附加到两个元素,而不是以编程方式创建事件:

$(".resume_box, #resume_upload").click(function(e) {
    e.stopPropagation(); // important, as it will prevent the event bubbling .: recursion
    // your logic here...
});

答案 1 :(得分:2)

其他答案都是正确的(event bubbling),这只是另一种解决方案:只需删除 resume_upload元素中的resume_box按钮即可。因此,触发按钮上的单击不会冒泡到框中,从而结束此调用堆栈。

<div class="resume_box">
  <div class="file_instructions"> Please use .pdf format</div>
  <div class="button_plate">Choose a file</div>
</div>
<input id="resume_upload" type="file" name="resume" style="display: none" />

这是一个有效的codepen

答案 2 :(得分:2)

因为事件在dom树中冒出来。因此,如果在子元素上触发相同的click,则会在父级上绑定click事件。

因此它会创建一个循环并导致错误。

解决方案是您可以在子元素上使用event.stopPropagation();

或将您的选择器更改为:

$(".resume_box > .button_plate").click(function () {

答案 3 :(得分:0)

由于事件传播,事件冒泡DOM树。

#resume_upload.resume_box之内。单击元素会发送一个冒泡到父级的事件。

在您的情况下,单击父对象会触发对子进程的单击,该子进程将传播到父进程的处理程序,然后再次触发子进程单击,这将调用父处理程序,依此类推。

您可以通过在单击内部元素时手动阻止传播来解决此问题:

$("#resume_upload").click(function (e) {
   e.stopPropagation();
});

答案 4 :(得分:0)

您在.resume_box的事件处理程序中触发.resume_box上的点击事件(因为点击事件会冒出DOM)。相反,只有在输入上没有点击输入时才会手动触发输入点击:

$(".resume_box").click(function ( e ) {
   if ( e.target.id !== 'resume_upload' )
       $("#resume_upload").trigger("click");
});