开发者问题收集

如何使用 jQuery 触发表格内的按钮?

2016-12-07
1043

我尝试在用户点击 <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 是正确的,但是我从控制台收到此错误:

Uncaught RangeError: Maximum call stack size exceeded

我的代码有什么问题,我不明白为什么一切对我来说似乎都是正确的?

2个回答

问题在于您的函数调用(处理 click 事件)是递归的。

jQuery 的 .on(...) 正在捕获指定选择器(在您的例子中为 tr 及其下方的所有内容 的点击事件。因此 tr 内部的按钮的 click 事件也会触发您定义的匿名函数。

在您的场景中,这是 不可取的 ,因为用户的点击会触发另一个 click 事件,进而触发另一个 click 事件,依此类推。

每次从函数内部调用函数都会在调用堆栈上生成一个新条目,最终会变得太大并崩溃。 (这是您所看到的症状。)只有当函数实际返回时,堆栈才会缩小……(这对您来说永远不会发生)。

您可以使用多种方法来避免此问题。可能最简单的方法:忘记在按钮本身上设置点击处理程序(因为按钮的点击会触发包含的 tr 点击事件)。

或者,您可以告诉 jQuery 停止在 DOM 树上应用点击事件……

引用有关此主题的 jQuery 文档:

By default, most events bubble up from the original event target to the document element.

At each element along the way, jQuery calls any matching event handlers that have been attached. A handler can prevent the event from bubbling further up the document tree (and thus prevent handlers on those elements from running) by calling event.stopPropagation() .

Any other handlers attached on the current element will run however.

To prevent that, call event.stopImmediatePropagation() . (Event handlers bound to an element are called in the same order that they were bound.)

引用: http://api.jquery.com/on/


在半相关的说明中,我强烈建议以一种尽可能清晰地分离事件处理程序、私有方法和公共方法的方式来构建您的 jQuery 代码。关于如何做到这一点,有各种各样的“建议”(我当然不能说是标准!) - 我个人最喜欢的是: https://stackoverflow.com/a/5947280/817132

使用此方法,我为所有 UI 代码创建一个“命名空间”(假设它只是一个小的代码库),并有一个“设置”函数(由 onReady 调用),它将所有事件处理程序连接到其相关选择器。这些事件处理程序尽可能少,主要是调用包含实际逻辑的私有函数。

出于 个人 偏好,我尽可能避免使用匿名函数。我改为附加对函数的引用。


在半相关的说明中...如果您还没有,我 强烈 建议您掌握浏览器的开发人员工具。 (我个人最喜欢的是 Chrome 附带的工具。)

特别研究 断点 并学习如何在使用 监视 逐行 (以及进出函数) 单步执行

例如: https://developers.google.com/web/tools/chrome-devtools/javascript/add-breakpoints

wally
2016-12-07

正如我在评论中提到的,原因是在同一个 TR 内的元素上递归生成点击事件。

在单击播放按钮之前,只需检查点击事件不是来自播放按钮:

$(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();
    }
  });
});
iCollect.it Ltd
2016-12-07