【问题标题】:Trigger a click event on an inner element在内部元素上触发点击事件
【发布时间】:2011-10-03 07:25:40
【问题描述】:

需要单击表格中的一行,其中每个第一个单元格都包含一个链接并打开一个 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:超出最大调用堆栈大小

如何以正确的方式触发对整行的点击,而不是仅触发链接,从而避免stackoverflow?

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

【问题讨论】:

  • 把它放在一个 jsfiddle 中,这样我们可以更恰当地帮助你
  • 我做了这个:jsfiddle.net/MarkKramer/F5aMb 我添加了 onclick 以查看它是否在模拟点击,它正在向a 注册点击,但它没有跟随链接。
  • 我修好了。在下面检查我的答案。
  • @Caspar Kleijne:查看我的更新。
  • @Caspar Kleijne,我解释了递归和一个微小的可重用解决方法。

标签: javascript jquery event-handling


【解决方案1】:

效果很好:

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

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

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

编辑:

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

当您建议触发点击时,您会导致递归:点击链接→fancybox→气泡→啊哈!表格行→触发链接点击→链接被点击...

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

为什么上面的代码有效——我们检查事件是否从链接冒泡。如果为真,我们只需返回并停止进一步传播。


查看更新的小提琴:http://jsfiddle.net/F5aMb/28/

【讨论】:

    【解决方案2】:

    试试

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

    【讨论】:

    • 我花了很长时间试图简化这样的事情。谢谢!
    【解决方案3】:

    试试这个:

    $("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.
    });
    

    更新:

    This will do.

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

    $(this).find("a").trigger('click');实际上并没有触发默认 锚标记行为。如果点击事件,它只是尝试触发点击事件 已明确绑定到该元素。

    【讨论】:

      【解决方案4】:

      可能是我误解了你的问题,但这不符合你的需要:

      $("table tr").click(function(e) {
          e.stopImmediatePropagation();
          if (! $(e.target).is('a')) {
              $(this).find("a").trigger('click');
          }
      });
      

      【讨论】:

        【解决方案5】:

        为了这个练习的有趣目的,这里是一个纯 js 解决方案,即不使用 jQ lib)。

        可在此处进行测试: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 可以返回一个节点或一个标记名,这听起来很不对。但是你只用它作为返回一个标签名。总体而言,相当混乱,难以理解,不是很有教学意义,也没有解决真正的问题。我确定您从中学到了一些东西,但我认为它对阅读此问题的其他人没有用
        • ShowEventSource 处理 Safari 错误,所以它不是 wong。整体可以解决问题,因此它以某种方式回答了问题,但没有 Jquery,这无助于真正理解 DOM 事件。
        • ShowEventSource is 是错误的,因为它的名字并没有说明它的作用,考虑到GetEventSource 已经做到了(但还不够好,所以另一个函数类似的名称用于解决其缺陷)
        • 清除。 ShowEventSource 并没有真正使用,因为它仅用于解释或教学目的,所以是的,当然,它以某种方式复制 GetEventSource。我认为这很明显。故事结束。
        【解决方案6】:

        试试

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

        【讨论】:

        • 这会产生同样的问题。
        【解决方案7】:

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

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

        在这里提琴:http://jsfiddle.net/3VMGn/2/

        【讨论】:

        • 是的,它确实记录了对链接的点击,但没有跟随链接,这就是他遇到的问题
        【解决方案8】:

        为了补偿冒泡,您需要检测事件的目标并且不要多次点击链接。 此外,jQuery 的“触发”功能不适用于纯链接,因此您需要专门的点击功能。

        你可以试试: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()
           }
        }
        

        【讨论】:

          【解决方案9】:

          我可以通过给每个链接一个唯一的 ID,然后使用 jQuery 设置该唯一 ID 的点击事件来将窗口重定向到适当的页面来做到这一点。

          这是我的工作示例:http://jsfiddle.net/MarkKramer/F5aMb/2/

          这里是代码:

          $('#link1').click(function(){
              // do whatever I want here, then redirect
              window.location.href = "detail.aspx?CID=67525";
          });
          $('#link2').click(function(){
              // do whatever I want here, then redirect
              window.location.href = "detail.aspx?CID=17522";
          });
          
          $("table tr").click(function(e) {
              e.stopImmediatePropagation();
              $(this).find("a").trigger('click');
          });
          

          【讨论】:

            【解决方案10】:

            你可以用下面的代码做你想做的事。我在你身上测试过 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();
              }
            });
            

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

            【讨论】:

              【解决方案11】:

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

              在此处查看示例http://jsfiddle.net/sethi/bEDPp/4/ .手动单击链接显示 2 个警报,而通过 jQuery 触发事件仅显示 1 个警报。

              你也可以参考这个链接:re-firing a click event on a link with 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 与锚元素绑定的事件。

              【讨论】:

                【解决方案12】:
                $('a.fancybox').click(function(evt){evt.stopPropagation())});
                
                $('table tr:has[.fancybox]').click(function(evt){
                $(this).find('.fancybox').trigger('click')
                })
                

                【讨论】:

                  【解决方案13】:

                  我想我有你要找的东西。您需要做的是在处理程序中的锚标记上调用click(),并确保忽略来自锚本身的事件。另外,WebKit 不支持click(),所以需要自己实现。

                  请注意下面的小提琴,它正确地跟随链接目标,即打开一个新窗口,或加载到同一个窗口中。 http://jsfiddle.net/mendesjuan/5pv5A/3/

                  // Some browsers (WebKit) don't support the click method on links
                  if (!HTMLAnchorElement.prototype.click) {
                      HTMLAnchorElement.prototype.click = function() {
                        var target = this.getAttribute('target');
                        var href = this.getAttribute('href');
                        if (!target) {
                            window.location = href;
                        } else {
                            window.open(href, target);
                        }          
                      }
                  }
                  
                  $("table tr").bind('click',function(e) {
                      // This prevents the stack overflow
                      if (e.target.tagName == 'A') {
                          return;
                      }
                      // This triggers the default behavior of the anchor
                      // unlike calling jQuery trigger('click')
                      $(this).find("a").get(0).click();
                  });
                  

                  【讨论】:

                    【解决方案14】:

                    我的用例是在单击 - 元素时触发单击。检查目标元素的类型解决了递归调用问题。

                    $('#table tbody td').click(function(e){
                        if ($(e.target).is('td')) {
                            $(this).find('input').trigger('click');
                        }
                    });
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-12-07
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-08-08
                      • 1970-01-01
                      • 2016-08-06
                      • 2018-12-24
                      相关资源
                      最近更新 更多