在一个内部元素上触发点击事件

18

表格中每行的第一个单元格都包含一个链接,需要点击该单元格并打开相应的URL。

<table>
  <tr>
    <td><a class="fancybox" href="detail.aspx?CID=67525">LT5C260A436C41</a></td> 
    <td>more data</td>
  </tr>
  <tr>
    <td><a class="fancybox" href="detail.aspx?CID=17522">LA5C260D436C41</a></td> 
    <td>more data</td>
  </tr>
  ...
</table>

fancybox 中,应该使整行可点击而不仅仅是链接以打开详细页面,即在页面本身中。

因此,我尝试做了这样的事情:

$("table tr").bind('click',function(e) {
    e.stopPropagation();
    $(this).find("a").trigger('click');
});

但似乎该事件递归冒泡导致:

未捕获的 RangeError: 超出最大调用堆栈大小

我该如何正确地触发整行的点击而不仅仅是链接,以避免出现堆栈溢出问题?

更新:我非常感谢下面的答案,但我的问题是有关触发事件而不是执行该事件中的行为。解决方法可能很好,但在这种情况下不适用。


把它放在 jsfiddle 上,这样我们可以更恰当地帮助你。 - Mark Kramer
我做了这个:http://jsfiddle.net/MarkKramer/F5aMb/ 我添加了onclick事件来检查它是否模拟了点击,它已经注册了对a的点击,但是没有跟随链接。 - Mark Kramer
@Caspar Kleijne:请看我的更新。 - user405398
@Caspar Kleijne,我给出了递归的解释和一个小巧的可重用解决方案。 - Lapple
14个回答

21

这个很有效:

$("table tr").click(function(e) {
    var $link = $(this).find("a");

    if (e.target === $link[0]) return false;

    $link.trigger('click');
    return false;
});

编辑:

为什么大多数解决方案都不起作用 - 它们失败了,因为当链接被单击时,附加的立即处理程序会运行。然后事件冒泡以查看是否将处理程序附加到了表格单元格、行等。

当你建议触发一个点击操作时,你会引起递归:链接被单击→fancybox→冒泡→哈!表格行→触发链接点击→链接被单击...

当你建议停止传播时,请注意事件停止向父元素冒泡,因此附加到的click处理程序将不会执行。

为什么上面的代码有效 - 我们检查事件是否是从链接冒泡而来。如果是,则简单地返回并停止进一步的传播。


请参见更新的 fiddle:http://jsfiddle.net/F5aMb/28/


10

尝试

$('table tr').click(function() {
  var href = $(this).find("a").attr("href");
    if(href) {
       window.location = href;
    }
});

1
我花了太长时间来尝试优化这样的东西。谢谢! - CarterMan

4
请尝试以下操作:
$("table tr a").bind('click', function(e) {
     e.preventDefault();
     window.open($(this).attr('href'));
     return false;
});

$("table tr").bind('click', function(e) {
     $(this).find("a").trigger('click');
 });

我发现了问题所在。
在你的代码中,
$("table tr").bind('click',function(e) {
e.stopPropagation();
$(this).find("a").trigger('click');//This line again triggers a click event binded on the tr ELEMENT which contains the 'a' ELEMENT. So it goes into a infinite loop.
});

Update:

This will do.

$("table tr").bind('click', function(e) {
   window.location.href = $(this).find("a.fancybox").attr('href');
});

$(this).find("a").trigger('click');实际上并不会触发默认的超链接行为。它只是在元素已被显式绑定了单击事件时尝试触发单击事件。


3
也许我误解了你的问题,但是这个做法不正是你所需要的吗:
$("table tr").click(function(e) {
    e.stopImmediatePropagation();
    if (! $(e.target).is('a')) {
        $(this).find("a").trigger('click');
    }
});

3
为了有趣的目的,这里提供了一个纯JS解决方案,即不使用jQuery库。
可在此处进行测试:http://jsfiddle.net/Sr5Vy/3/
<table>
  <tr id="node_1">
    <td><a class="fancybox" href="detail.aspx?CID=67525">LT5C260A436C41</a></td>
    <td>more data</td>
  </tr>
  <tr id="node_2">
    <td><a class="fancybox" href="detail.aspx?CID=17522">LA5C260D436C41</a></td>
    <td>more data</td>
  </tr>
</table>

function AddEvent(id, evt_type, ma_fonction, phase) {
  var oElt = document.getElementById(id);
  if( oElt.addEventListener ) {
      oElt.addEventListener(evt_type, ma_fonction, phase);
  } else if( oElt.attachEvent ) {
      oElt.attachEvent('on'+evt_type, ma_fonction);
  }

    // Debug
    // alert('a \'' + evt_type + '\' event has been attached on ' + id );

    return false;
}

function getElementsByRegExpOnId(search_reg, search_element, search_tagName) {
    search_element = (search_element === undefined) ? document : search_element;
    search_tagName= (search_tagName === undefined) ? '*' : search_tagName;
    var id_return = new Array;
    for(var i = 0, i_length = search_element.getElementsByTagName(search_tagName).length; i < i_length; i++) {
        if (search_element.getElementsByTagName(search_tagName).item(i).id &&
        search_element.getElementsByTagName(search_tagName).item(i).id.match(search_reg)) {
            id_return.push(search_element.getElementsByTagName(search_tagName).item(i).id) ;
        }
    }
    return id_return; // array
}

function FollowSpecialLinks(event) {

    // Debug
    // alert('event was successfully attached');

    // Prevent propagation
    event.preventDefault();

    // Identify targetted node (eg one of the children of <tr>)
    var targetted_elt = ShowEventSource(event);
    //alert('Event\'s target : ' + targetted_elt);

    // Extract the targetted url
    if (targetted_elt == "A") {
        var current_link = GetEventSource(event).href;

    } else {
        var current_tr = GetEventSource(event).parentNode;
        var child_links = current_tr.getElementsByTagName('a');
        var current_link = child_links[0].href;
    }



   // Now open the link
    if(current_link) {
        // Debug  
        alert('will now open href : ' + current_link);
       window.location = current_link;
    }


}

function GetEventSource(event) {
    var e = event || window.event;
    var myelt = e.target || e.srcElement;
    return myelt;
}

function ShowEventSource(event) {
    var elmt;
    var event = event || window.event;            // W3C ou MS
    var la_cible = event.target || event.srcElement;
    if (la_cible.nodeType == 3)            // Vs bug Safari
        elmt = la_cible.parentNode;                        
    else
        elmt = la_cible.tagName;
   return elmt;
}

// Get all document <tr> id's and attach the "click" events to them
  my_rows = new Array();
  my_rows = getElementsByRegExpOnId(/^node_.+/, document , 'tr') ;
    if (my_rows) {
        for (i=0; i< my_rows.length; i++ ) {
            var every_row = document.getElementById( my_rows[i] ) ;
            AddEvent(every_row.id, 'click', FollowSpecialLinks, false);
        }
    }

ShowEventSourceGetEventSource有什么区别?ShowEventSource可以返回节点或标记名称,这听起来非常不正确。但你只使用它作为返回标记名称。总体而言,这很混乱,难以理解,不太具有教学意义,并且没有回答真正的问题。我相信你从中学到了一些东西,但我认为对于其他阅读此问题的人来说并不实用。 - Ruan Mendes
ShowEventSource 处理 Safari 的 bug,所以它并没有错。总体来说,它能解决问题,但是没有使用 jQuery,这样就不能真正理解 DOM 事件。 - hornetbzz
ShowEventSource 的命名并不准确,因为它的名称并没有表明它的功能,考虑到 GetEventSource 已经做到了这一点(但并不够好),因此另一个类似命名的函数被用来解决其缺陷。 - Ruan Mendes
清除。ShowEventSource并没有真正被使用,它只是为了解释或教学目的而存在,所以是的,毫无疑问,它在某种程度上重复了GetEventSource。我认为这很明显。故事结束。 - hornetbzz

2
为了补偿冒泡,你需要检测事件的目标,并且不要点击链接超过一次。 此外,jQuery的“trigger”函数不适用于普通链接,因此你需要一个专门的点击函数。
你可以在这里试用它:http://jsfiddle.net/F5aMb/27/
$("table tr").each(function(i, tr){
    $(tr).bind('click',function(e) {
        var target = $(e.target);
        if( !target.is("a") ) {
            clickLink($(this).find("a")[0]);
        }
    })
});


function clickLink(element) {
   if (document.createEvent) {
       // dispatch for firefox + others
       var evt = document.createEvent("MouseEvents");
       evt.initEvent("click", true, true ); // event type,bubbling,cancelable
       return !element.dispatchEvent(evt);
   } else {
       //IE
       element.click()
   }
}

2

尝试

$(".fancybox").parent('td').parent('tr').bind('click',function(e) {
    e.stopPropagation();
    $(this).find("a").trigger('click');
});

那会造成同样的问题。 - Felix Kling

2

您是否尝试在单击链接时停止立即传播?这样一来,您应该可以停止递归。

$('a').click(function(e){
    e.stopImmediatePropagation();
    alert('hi');
});

fiddle here: http://jsfiddle.net/3VMGn/2/


是的,它确实会注册链接上的点击,但是不会跟随链接,这就是他遇到的问题。 - Mark Kramer

1

您可以使用以下代码实现您想要的功能。我已在 jsfilddle 上测试过,似乎可以正常工作。

$("table tr").click(function(e) {

   // check if click event is on link or not.
   // if it's link, don't stop further propagation
   // so, link href will be followed.

  if($(e.target).attr('class')=='fancybox'){
    alert('you clicked link, so what next ?.');

  // else if click is happened somewhere else than link, 
  // stop the propagation, so that it won't go in recursion.

  }else{
    alert('no link clicked, :( ');
    alert('now clicking link prgrammatically');
    $(this).find('a').click(); 
    e.preventDefault();
  }
});

如果您想实现其他目标,请告诉我。


1

我认为.click().trigger("click")只会触发onclick的事件处理程序。

在这里可以看到一个示例http://jsfiddle.net/sethi/bEDPp/4/。手动点击链接会显示2个警报,而通过jQuery触发事件只会显示1个警报。

您还可以参考此链接:使用jQuery重新触发链接上的单击事件

解决方案

如果您只想打开一个fancybox,请尝试以下方法:

$("table tr").bind('click',function(e) {
        var elem = $(e.target);
        if(elem.is('a')){
            return;    
        }
        e.stopImmediatePropagation();
        var parent= elem.is('tr') ? elem:elem.parents("tr").eq(0);
        parent.find("a").trigger('click.fb');
    });

其中click.fb是fancybox与锚点元素绑定的事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接