开发者问题收集

.trigger() jquery 函数导致 Uncaught RangeError:超出最大调用堆栈大小

2018-08-15
2623

我有两个带有动态链接的 div,它们有时被填充,有时不被填充。如果您单击如下所示的链接:

<a href="#">

什么都没有发生,我阻止了默认操作,但如果链接是:

<a href="/path/to/a/page">

它将跟随。

我希望能够单击周围的 div,并使用与上述相同的逻辑。因此,如果我单击红色并且有一个有效链接,则链接将跟随。我正在使用 trigger() 来尝试此操作。

情况如下:

$(function() {
	$(".container").click(function(e) {
    var clickTarget = $(e.target).attr("href");
    var clickTargetLink = $(this).find(".container-link");
      if ((clickTarget != "#") || (clickTarget != undefined)) {
        clickTargetLink.trigger("click");
      } else {
        e.preventDefault();
      }
  });
});
.container {
  padding: 50px;
  margin-bottom: 1rem;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="google.com">link</a>
</div>
<div class="container">
  <a class="container-link" href="#">link</a>
</div>

最终发生的是点击链接中带有 google.com 的红色 div 抛出:

jquery.js:3988 Uncaught RangeError: Maximum call stack size exceeded at String.replace () at camelCase (jquery.js:3988) at Data.get (jquery.js:4069) at HTMLDivElement.dispatch (jquery.js:5146) at HTMLDivElement.elemData.handle (jquery.js:4991) at Object.trigger (jquery.js:8249) at HTMLAnchorElement. (jquery.js:8327) at Function.each (jquery.js:354) at jQuery.fn.init.each (jquery.js:189) at jQuery.fn.init.trigger (jquery.js:8326)

超出最大调用堆栈大小错误 - 这表明此代码中的某处存在无限循环。我不知道这里怎么会这样?

为什么此代码会导致最大调用堆栈大小错误?

编辑:进一步研究让我发现: 触发器单击时超出最大调用堆栈大小

继续

.triggerHandler() 什么都没呈现,链接也跟不上。我是否需要使用我不知道的其他操作?

编辑 #2:更多详细信息:

  1. 我无法更改/添加标记结构。
  2. 红色 div 需要完全可点击,因为当链接为空时,还有另一个操作与之相关: <a href="#">
  3. 我尝试了 e.stopPropagation(); - 它解决了错误,但链接无法跟随
  4. 我尝试了 triggerHandler() - http://api.jquery.com/triggerhandler/
3个回答

您的点击处理程序正在触发一个新的点击事件,该事件由点击处理程序处理,该点击事件又触发一个新的点击事件,该事件由点击处理程序处理,最终导致堆栈溢出。

在评论中(现在在更新的问题中),您已经阐明了此代码的用途:

The red area needs to be clickable, not just the link. That's why I'm trying to use .trigger() so that I can trigger a click in the child link inside the div when the div is clicked on.

这需要进行一些更改,而不仅仅是修复无限循环:

  • 您现有的代码正在事件目标本身上寻找 href ,这不会允许红色区域可点击(因为事件目标不一定是具有 href 属性的元素)。我已将其更改为忽略事件目标(这不是您真正关心的),而是仅从容器元素内的链接中提取 href。

  • 在您的 if 子句中,您使用了 || ,而您想说的是 && (“如果不是 X 或不是 Y”将始终为真;“如果不是 X 并且 不是 Y”是您在此处的意思。)

此处通过直接设置窗口位置而不是触发另一个点击事件来解决无限递归。

$(function() {
  $(".container").click(function(e) {
    var clickTarget = $(this).find("a.container-link").attr("href");
    if (clickTarget && clickTarget !== "#") {
      window.location=clickTarget;
    } else {
      // prevent link navigation from occurring
      console.log("Blocking click");
      e.preventDefault();
    }
  });
});
.container {
  padding: 10px;
  margin-bottom: 1rem;
  background-color: red;
  cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="https://example.com">Normal link</a>
</div>
<div class="container">
  <a class="container-link" href="#">Blocked link</a>
</div>
Daniel Beck
2018-08-15

您可以选择检查点击的是链接还是容器。如果是链接,则不要触发另一次点击。

$(function() {
  $(".container").click(function(e) {
    var $containerLink = $(this).find('.container-link');
    //check to see if the container was clicked, or if the link was clicked
    var linkWasClicked = $(e.target).is('.container-link');
    
    if (['#', undefined].indexOf($containerLink.attr('href')) > -1) {
      e.preventDefault();
    } else if (!linkWasClicked) { //only trigger the link if it was not clicked
      $containerLink[0].click();
    }
  });
});
.container {
  padding: 50px;
  margin-bottom: 1rem;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="https://google.com">link</a>
</div>
<div class="container">
  <a class="container-link" href="#">link</a>
</div>
Taplar
2018-08-15

单击容器时,您会触发对其内部链接的单击,该单击会传播回容器,再次单击链接,依此类推。您正在以递归方式一遍又一遍地单击链接,这会导致错误。在容器的 click 事件处理程序中,您需要检查事件的 currentTarget 是否等于事件的单击链接目标(防止递归)。要触发单击链接以重定向到另一个页面,您需要获取要单击的实际 DOM 元素(而不是 jQuery 对象),如下所示: clickTargetLink[0].click() (jQuery 始终返回元素数组)。

.container {
  padding: 50px;
  margin-bottom: 1rem;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="http://www.example.com">link</a>
</div>
<div class="container">
  <a class="container-link" href="#">link</a>
</div>
<script>
$(function() {
	$(".container").click(function(e) {
    var clickTarget = $(e.target).attr("href");
    var clickTargetLink = $(this).find(".container-link");
      if (e.currentTarget==e.target) {
        clickTargetLink[0].click();
      } else {
       if(clickTarget!==undefined&&clickTarget == "#"){
       e.preventDefault();
       }
      }
  });
});
</script>
Unmitigated
2018-08-15