动态创建的元素上的事件绑定?

IT技术 javascript jquery events unobtrusive-javascript
2020-12-16 21:02:54

我有一些代码,我循环浏览页面上的所有选择框并将.hover事件绑定到它们以对它们的宽度进行一些调整mouse on/off

这发生在页面准备好并且工作正常。

我遇到的问题是,我在初始循环后通过 Ajax 或 DOM 添加的任何选择框都不会绑定事件。

我找到了这个插件(jQuery Live Query Plugin),但是在我使用插件向我的页面添加另一个 5k 之前,我想看看是否有人知道一种方法来做到这一点,无论是直接使用 jQuery 还是通过其他选项。

6个回答

从 jQuery 1.7 开始,您应该使用jQuery.fn.on填充的选择器参数:

$(staticAncestors).on(eventName, dynamicChild, function() {});

解释:

这称为事件委托,其工作原理如下。该事件附加到staticAncestors应处理的元素的静态父级 ( )。每次在此元素或后代元素之一上触发事件时,都会触发此 jQuery 处理程序。然后处理程序检查触发事件的元素是否与您的选择器 ( dynamicChild)匹配当匹配时,您的自定义处理程序函数将被执行。


在此之前,推荐的方法是使用live()

$(selector).live( eventName, function(){} );

然而,live()在 1.7 中被弃用on(),而在 1.9 中被完全删除。live()签名:

$(selector).live( eventName, function(){} );

... 可以替换为以下on()签名:

$(document).on( eventName, selector, function(){} );

例如,如果您的页面使用类名动态创建元素,dosomething您会将事件绑定到已经存在的父级(这是这里问题的核心,您需要绑定到存在的东西,不要绑定到动态内容),这可以(也是最简单的选项)是document. 尽管记住document可能不是最有效的选择

$(document).on('mouseover mouseout', '.dosomething', function(){
    // what you want to happen when mouseover and mouseout 
    // occurs on elements that match '.dosomething'
});

事件绑定时存在的任何父级都可以。例如

$('.buttons').on('click', 'button', function(){
    // do something here
});

将适用于

<div class="buttons">
    <!-- <button>s that are generated dynamically and added here -->
</div>
在此处了解有关事件委托的更多信息:learn.jquery.com/events/event-delegation
2021-02-25 21:02:54
这是天才的平方!它不仅有助于解决我眼前的问题,而且还有助于使用 on() 和 jquery 构建事件委托。非常欣赏。
2021-03-07 21:02:54

的文档中有很好的解释jQuery.fn.on

简而言之:

事件处理程序仅绑定到当前选定的元素;在您的代码调用 时,它们必须存在于页面上.on()

因此在下面的示例中#dataTable tbody tr必须存在于代码生成之前。

$("#dataTable tbody tr").on("click", function(event){
    console.log($(this).text());
});

如果将新 HTML 注入页面,则最好使用委托事件来附加事件处理程序,如下所述。

委托事件的优点是它们可以处理来自稍后添加到文档的后代元素的事件。例如,如果表存在,但使用代码动态添加行,以下将处理它:

$("#dataTable tbody").on("click", "tr", function(event){
    console.log($(this).text());
});

除了它们能够处理尚未创建的后代元素上的事件之外,委托事件的另一个优点是当必须监视许多元素时,它们的潜在开销要低得多。在包含 1,000 行的数据表上tbody,第一个代码示例将处理程序附加到 1,000 个元素。

委托事件方法(第二个代码示例)仅将事件处理程序附加到一个元素tbody,并且事件只需要冒泡一层(从单击trtbody)。

注意:委托事件不适用于SVG

这是一个没有任何库或插件纯 JavaScript解决方案:

document.addEventListener('click', function (e) {
    if (hasClass(e.target, 'bu')) {
        // .bu clicked
        // Do your thing
    } else if (hasClass(e.target, 'test')) {
        // .test clicked
        // Do your other thing
    }
}, false);

这里hasClass

function hasClass(elem, className) {
    return elem.className.split(' ').indexOf(className) > -1;
}

Live demo

归功于 Dave 和 Sime Vidas

使用更现代的 JS,hasClass可以实现为:

function hasClass(elem, className) {
    return elem.classList.contains(className);
}

下面嵌入了相同的 jsfiddle Live 演示:

function hasClass(elem, className) {
  return elem.classList.contains(className);
}

document.addEventListener('click', function(e) {
  if (hasClass(e.target, 'bu')) {
    alert('bu');
    document.querySelector('.bu').innerHTML = '<div class="bu">Bu<div class="tu">Tu</div></div>';
  } else if (hasClass(e.target, 'test')) {
    alert('test');
  } else if (hasClass(e.target, 'tu')) {
    alert('tu');
  }

}, false);
.test,
.bu,
.tu {
  border: 1px solid gray;
  padding: 10px;
  margin: 10px;
}
<div class="test">Test
  <div class="bu">Bu</div>test
</div>

冒泡呢?如果点击事件发生在您感兴趣的元素的子元素上怎么办?
2021-02-10 21:02:54
一篇关于如何使用 vanilla 脚本而不是 jQuery 来完成任务的好文章 - toddmotto.com/...
2021-02-20 21:02:54
Element.classList较旧的浏览器不支持@EugenKonkov 例如,IE < 9。
2021-02-21 21:02:54
您可以使用Element.classList而不是拆分
2021-03-04 21:02:54

您可以在创建对象时向对象添加事件。如果您要在不同时间向多个对象添加相同的事件,则创建命名函数可能是最佳选择。

var mouseOverHandler = function() {
    // Do stuff
};
var mouseOutHandler = function () {
    // Do stuff
};

$(function() {
    // On the document load, apply to existing elements
    $('select').hover(mouseOverHandler, mouseOutHandler);
});

// This next part would be in the callback from your Ajax call
$("<select></select>")
    .append( /* Your <option>s */ )
    .hover(mouseOverHandler, mouseOutHandler)
    .appendTo( /* Wherever you need the select box */ )
;

您可以简单地将事件绑定调用包装到一个函数中,然后调用它两次:一次是在文档准备好之后,一次是在添加新 DOM 元素的事件之后。如果这样做,您将希望避免在现有元素上两次绑定相同的事件,因此您需要取消绑定现有事件或(更好)仅绑定到新创建的 DOM 元素。代码看起来像这样:

function addCallbacks(eles){
    eles.hover(function(){alert("gotcha!")});
}

$(document).ready(function(){
    addCallbacks($(".myEles"))
});

// ... add elements ...
addCallbacks($(".myNewElements"))
这篇文章真的帮助我了解了一个问题,我在加载相同的表单并收到 1,2,4,8,16... 提交时。而不是使用 .live() 我只是在我的 .load() 回调中使用了 .bind() 。问题解决了。谢谢!
2021-03-04 21:02:54