当用户单击<tr>标记对象时,我试图触发一个按钮(在我的表中),如下所示:
$(document).ready(function(){
$('body').on('click', 'tr', function(){
var tridx = $(this).data('track-id');
$('td div#play'+tridx).click();
});
});<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="sortable">
<thead>
<tr>
<th data-sort="nope">id</th>
<th data-sort="name">Artist</th>
<th data-sort="name">Title</th>
<th data-sort="name">Genre</th>
<th data-sort="duration">Duration</th>
<th data-sort="date">Release</th>
</tr>
</thead>
<tbody>
<tr data-track-id="252">
<td>
<div data-track-name="1" data-track-id="252" id="play252" class="playbtn252" style="display: none;"></div>
<div id="countlist252" data-count-list="1" style="display: block;">1</div>
</td>
<td>Simon Deoro</td>
<td>1</td>
<td>1</td>
<td>3:47</td>
<td>2016-12-06</td>
</tr>
<!-- more tr -->
</tbody>
</table>
tridx是正确的,但是我从控制台获得了这个错误:
未指定的RangeError:超过最大调用堆栈大小
我的代码出了什么问题,我无法理解,对我来说似乎一切都是正确的?
发布于 2016-12-07 10:57:23
正如我在注释中提到的,原因是递归地在同一个TR中的元素上生成一个click事件。
单击“播放”按钮之前,只需检查单击事件是否来自play按钮:
$(document).ready(function(){
$('body').on('click', 'tr', function(e){
var tridx = $(this).data('track-id');
var $button = $('td div#play'+tridx);
if (!$button.is(e.target))
{
$button.click();
}
});
});发布于 2016-12-07 10:56:13
问题是函数调用(处理click事件)是递归的。
jQuery的.on(...)是为指定的选择器(在您的示例中是tr)及其下面的所有内容捕获单击事件。因此,click中按钮的tr事件也会触发您定义的匿名函数。
在您的场景中,这是不需要的,因为用户的单击会触发另一个click事件,触发另一个click事件,依此类推。
从函数内部对函数的每一次调用都会在调用堆栈上生成一个新条目,该条目最终会变得太大并会掉下来。(这就是你看到的症状。)只有当函数实际返回时,堆栈才会缩小.(这永远不会发生在你身上)。
有多种方法可以避免这个问题。可能是最简单的:忘记在按钮本身上有一个单击处理程序(因为按钮的单击无论如何都会触发包含tr的单击事件)。
或者,您可以告诉jQuery停止将单击事件应用到DOM树上.
引用有关此主题的jQuery文档:
默认情况下,大多数事件从原始的事件目标上升到文档元素。 在此过程中的每个元素中,jQuery都会调用已附加的任何匹配的事件处理程序。通过调用
event.stopPropagation(),处理程序可以防止事件在文档树上进一步冒泡(从而防止这些元素上的处理程序运行)。 但是,附加在当前元素上的任何其他处理程序都将运行。 为了防止这种情况,打电话给event.stopImmediatePropagation()。(绑定到元素的事件处理程序的调用顺序与绑定顺序相同。)
在一个半相关的说明中,我强烈建议以一种尽可能清晰的方式构造您的jQuery代码,使事件处理程序与私有方法与公共方法之间的分离尽可能清楚。有各种各样的“推荐”(我当然不能说标准!)关于如何做到这一点,我个人最喜欢的是:https://stackoverflow.com/a/5947280/817132
使用这种方法,我为所有UI代码(假设它只是一个小的代码库)创建了一个“命名空间”,并有一个“安装”函数(由onReady调用),它将所有事件处理程序连接到它们的相关选择器。这些事件处理程序尽可能最小化,主要是调用包含真实逻辑的私有函数。
作为个人喜好,我尽量避免匿名功能。我将引用函数作为替代。
半相关的音符.如果你还没有,我会强烈建议去掌握你的浏览器的开发工具。(我个人最喜欢的是Chrome的产品。)
具体来说,查看断点,并学习如何在使用监视时逐行地步骤(以及函数的进进出出)。
例如:https://developers.google.com/web/tools/chrome-devtools/javascript/add-breakpoints
https://stackoverflow.com/questions/41015409
复制相似问题