问题 如何使用jQuery(...)动态绑定到多个事件


我正在尝试创建杠杆jQuery的.on()(ex-live())来绑定多个事件。它适用于document.ready上存在的元素,但如果我在页面加载后动态添加第二个链接,则不会触发我的事件处理程序。

这是有道理的,因为最外层的方法遍历元素,并且doenst侦听新添加的DOM节点等.on(..)是侦听新DOM节点的东西,但需要事件名称参数,我不这样做直到我拥有DOM节点。

看起来像小鸡和鸡蛋的情况。

思考?

<a href="/foo.html" class="js-test" data-test-events="['click', 'mouseover']">Test 1</a>
<a href="/foo.html" class="js-test" data-test-events="['mouseout']">Test 2</a>

$(function() { 
    $('.js-test').each(function() { 
        var $this = $(this);
        var e, events = $this.data('test-events');

        for(e in events) {
            $this.on(events[e], function() {
                console.log("hello world!")
            });
        }
    });
}); 

更新,以下似乎也有效; $(this)似乎没有在正确的范围内。

<a href="/foo.html" class="js-test" data-test-events="click mouseover">Test 1</a>
<a href="/foo.html" class="js-test" data-test-events="mouseout">Test 2</a>

$(function() { 
    $('.js-test').on($(this).data('test-events'), function() { 
        // call third party analytics with data pulled of 'this'
    });
});     

更新1:

我认为我最好的选择是为我想要支持的所有方法创建特殊的.on方法,如下所示:

$(document).on('click', '.js-test[data-test-events~="click"]' function(event) {
    record(this, event);
});

$(document).on('mouseover', '.js-test[data-test-events~="mouseover"]', function(event) {
    record(this, event);
});

 ... etc ...

9675
2018-05-26 16:28


起源

你真的想做什么?定义没有任何函数的事件的元素没有意义,除非你真的想要任何事件只是记录 "hello world" (运行相同的功能) - Esailija
我挂钩进入分析API - 所以当作者编辑页面时,有一个界面让他们说“当这个元素触发事件X,Y,Z并且我想将数据发送到分析API时 - 数据被设置为其他数据 - *与问题机制无关的属性。 - empire29


答案:


$('a.js-test').on('click mouseover', function(event) {
  // you can get event name like following
  var eventName = event.type; // return mouseover/ click
  console.log(eventName);
  // you code
  console.log('Hello, World!');
});

示例示例

如果你想要现场活动,那么:

$('body').on('click mouseover', 'a.js-test', function(event) {
  // you can get event name like following
  var eventName = event.type; // return mouseover/ click
  console.log(eventName);
  // you code
  console.log('Hello, World!');
});

根据你的上一次编辑试试这个:

$('.js-test').on($('.js-test').data('test-events'), function() {
    console.log("hello world!")
});

编辑示例

以及现场活动授权

$('body').on($('.js-test').data('test-events'), '.js-test', function() {
    console.log("hello world!")
});

15
2018-05-26 16:29



不会有副作用吗? - Parth Thakkar
$('。js-test')。on($(this).data('test-events'),function(){console.log('Hello World');}其中data-test-events =“onclick mouseover“似乎确实有效。我通过data- *属性传递我的事件 - empire29
任何.js-test元素都可以定义它想要的任何事件。 click和mouseover就是例子。 - empire29
@ empire29根据您的上次编辑检查我的更新答案和演示 - thecodeparadox
@thecodeparadox - 仅当所有.js-test元素在data-test-events中具有相同的事件calue时才有效。 - empire29


害怕你不能这样做,因为你需要提供带有DOM元素或事件名称的jQuery。 您可以手动将事件绑定到新的DOM元素,也可以绑定可能在数据测试事件中的所有可能事件(如果您有3-5个事件,所有DOM事件将成为一个愚蠢而缓慢的解决方案)并检查您是否元素有其中之一:

$('body').on("mouseover click mouseout mouseenter mouseleave", '.js-test', function(e) {
    if (!$.inArray(e.type, $(this).data('test-events').split(' '))) {
        return;
    }
    console.log("hello world!");
});​

1
2018-05-26 22:20



这会非常慢吗?如果基本上一切都是火灾的事件?页面上可能有100个要绑定的元素(通常只有1或2个事件)。我正在查看旧的liveQuery插件,它似乎提供了我正在寻找的功能,除了它很老。 - empire29
您如何看待我的原始帖子的更新1?它不是很优雅,但似乎它的性能要高得多 一切 事件。思考? - empire29
@ empire29实际上它与将它们设置在一个“on”(就像在我的回答中)相同。你也对每个事件都有约束力,我认为它不是更高效。 inArray检查很快,但事件处理不是。测量速度。 - meze
在我的Update 1中,我只会将事件绑定到data-test-events匹配的元素。是不是听到了调用eventHandlers(即使他们所做的只是检查数组并立即返回,如果他们不匹配?)。这个开销可以忽略不计吗?即使是100多个元素? - empire29
@ empire29: Each time the event occurs, jQuery must compare all selectors of all attached events of that type to every element in the path...。所以jquery在引擎盖下做了同样的事情 ~= 可能没那么快 $.inArray。 - meze


如果要在将匹配元素添加到DOM时触发事件,您可能需要查看livequery - http://docs.jquery.com/Plugins/livequery


0
2018-05-26 23:35



没关系,只是看到你已经在评论中提到了另一个答案......无论它的年龄如何,它都适用于我用过它的东西,即使是最近版本的jQuery。 - Paul Fenney


此代码允许您将多个事件处理程序注册为函数数组。它经过测试和运行。看到这个 jsfiddle演示和测试用例

JavaScript的:

$(document).ready(function() {
    eventFnArray = [];
    eventFnArray["click"] = function(e) { 
        if(e.type != "click") return ;
        alert("click event fired - do xyz here");
        // do xyz
    };
    eventFnArray["mouseover"] = function(e) { 
        if(e.type != "mouseover") return ;
        alert("mouseover fired - do abc here"); 
        // do abc
    };
    eventFnArray["mouseout"] = function(e) { 
        if(e.type != "mouseout") return ;
        alert("mouseout fired - do JKL here"); 
        // do JKL
    };

    $('.js-test').each( (function(fn) { 

        return function(i) {   
            if(i != 0) return;
            var _that = this;
            var events = [];
            events = $(_that).attr("data-events").split(" ");

 //           alert($(_that).attr("data-events") + " : " + events.join(" "));

            $(this).parent().on(
                events.join(" "), 
                '.js-test', 
                function() {
                    console.info("hello - this is the " + event.type + " event");
      //             alert("data-events = " + $(this).attr("data-events") + " : event.type = " + event.type);
                    // delegate to the correct event handler based on the event type
                    if($(this).attr("data-events").indexOf(event.type) != -1)
                        fn[ event.type ](event);
                }
            );
        } 
    })(eventFnArray));    // pass function array into closure

});

HTML:

<div id="container">
    <a href="#" class="js-test" data-events="click mouseout mouseover">Test 1</a>
    <a href="#" class="js-test" data-events="mouseover">Test 2</a>
</div>

测试添加更多元素:

以下是3个测试用例:

// adds a link with the click event attached.
$('#container').append("<a href='#' class='js-test' data-events='click'>TEst333</a>");

// adds a link with the mouseover event 
$('#container').append("<a href='#' class='js-test' data-events='mouseover'>TEst444</a>");

// adds a link with mouseout
$('#container').append("<a href='#' class='js-test' data-events='mouseout'>TEs555</a>");

// adds a link with both mouseover and mouseout attached
$('#container').append("<a href='#' class='js-test' data-events='mouseout mouseover'>TEstLast</a>");

// mouseout and click
$('#container').append("<a href='#' class='js-test' data-events='mouseout click'>TEstLastForREAL</a>");

提醒:

我注意到你的一个链接同时附加了点击和鼠标悬停。虽然此代码将处理每个链接的多个事件,如上一个测试用例所示,但如果存在mouseover事件,则不会触发click事件。

这不是上述代码中的错误,而是处理事件的方式,如下所示:

// mouseover and mouseout fire, but not the click event
$('#container').on('mouseover mouseout click', '.js-test',function() { alert("afdas " + event.type); });

0
2018-05-29 03:55