Event binding on dynamically created elements?
我有一些代码,我在其中循环浏览页面上的所有选择框,并将
这在页面上发生,并且工作正常。
我遇到的问题是,在初始循环之后,通过Ajax或DOM添加的任何选择框都不会绑定事件。
我找到了这个插件(jquery live query plugin),但是在我用插件向我的页面添加另一个5K之前,我想看看是否有人知道这样做的方法,直接使用jquery还是通过另一个选项。
从jquery 1.7开始,您应该使用
1 | $(staticAncestors).on(eventName, dynamicChild, function() {}); |
在此之前,建议的方法是使用
1 | $(selector).live( eventName, function(){} ); |
然而,在1.7中,为了支持
1 | $(selector).live( eventName, function(){} ); |
…可替换为以下
1 | $(document).on( eventName, selector, function(){} ); |
例如,如果您的页面正在动态地创建类名为
1 2 3 4 | $(document).on('mouseover mouseout', '.dosomething', function(){ // what you want to happen when mouseover and mouseout // occurs on elements that match '.dosomething' }); |
绑定事件时存在的任何父级都可以。例如
1 2 3 | $('.buttons').on('click', 'button', function(){ // do something here }); |
适用于
1 | <!-- <button>s that are generated dynamically and added here --> |
在
简而言之:
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to
.on() .
因此,在下面的示例中,在生成代码之前,
1 2 3 | $("#dataTable tbody tr").on("click", function(event){ console.log($(this).text()); }); |
如果向页面中注入新的HTML,最好使用委托事件来附加事件处理程序,如下所述。
委托事件的优点是,它们可以处理以后添加到文档中的后代元素中的事件。例如,如果表存在,但行是使用代码动态添加的,那么下面将处理它:
1 2 3 | $("#dataTable tbody").on("click","tr", function(event){ console.log($(this).text()); }); |
除了能够处理尚未创建的子代元素上的事件之外,委托事件的另一个优点是,当必须监视许多元素时,它们的开销可能要低得多。在其
委托事件方法(第二个代码示例)只将事件处理程序附加到一个元素,即
注意:委派事件不适用于SVG。
这是一个没有任何库或插件的纯JavaScript解决方案:
1 2 3 4 5 6 7 8 9 | 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); |
其中
1 2 3 | function hasClass(elem, className) { return elem.className.split(' ').indexOf(className) > -1; } |
Live演示
信用卡给了戴夫和西蒙·维达斯
使用更现代的JS,
1 2 3 | function hasClass(elem, className) { return elem.classList.contains(className); } |
创建对象时,可以将事件添加到对象中。如果您在不同的时间将相同的事件添加到多个对象中,那么创建一个命名函数可能是一种方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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元素。代码如下所示:
1 2 3 4 5 6 7 8 9 10 | function addCallbacks(eles){ eles.hover(function(){alert("gotcha!")}); } $(document).ready(function(){ addCallbacks($(".myEles")) }); // ... add elements ... addCallbacks($(".myNewElements")) |
尝试使用
您可以使用live()方法将元素(甚至是新创建的元素)绑定到事件和处理程序,如onclick事件。
下面是我编写的一个示例代码,在这里您可以看到live()方法如何将所选元素(甚至是新创建的元素)绑定到事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> Untitled Document </head> <body> <script src="http://code.jquery.com/jquery-latest.js"> <script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/jquery-ui.min.js"> <input type="button" id="theButton" value="Click" /> <script type="text/javascript"> $(document).ready(function() { $('.FOO').live("click", function (){alert("It Works!")}); var $dialog = $('').html('<input type ="button" id="CUSTOM" value="click"/>This dialog will show every time!').dialog({ autoOpen: false, tite: 'Basic Dialog' }); $('#theButton').click(function() { $dialog.dialog('open'); return('false'); }); $('#CUSTOM').click(function(){ //$('#container').append('<input type="button" value="clickmee" class="FOO" /></br>'); var button = document.createElement("input"); button.setAttribute('class','FOO'); button.setAttribute('type','button'); button.setAttribute('value','CLICKMEE'); $('#container').append(button); }); /* $('#FOO').click(function(){ alert("It Works!"); }); */ }); </body> </html> |
动态创建的元素上的事件绑定
单一元素:
1 | $(document.body).on('click','.element', function(e) { }); |
子元素:
1 | $(document.body).on('click','.element *', function(e) { }); |
注意添加的
我注意到:
1 | $(document.body).on('click','.#element_id > element', function(e) { }); |
它已经不起作用了,但它以前也起作用了。我一直在使用来自google cdn的jquery,但我不知道他们是否更改了它。
另一种解决方案是在创建元素时添加侦听器。不是把监听器放在主体中,而是把监听器放在元素中创建它的那一刻:
1 2 3 4 5 6 7 8 9 10 11 | var myElement = $('<button/>', { text: 'Go to Google!' }); myElement.bind( 'click', goToGoogle); myElement.append('body'); function goToGoogle(event){ window.location.replace("http://www.google.com"); } |
我更喜欢使用选择器并将其应用于文档。
这将在文档上绑定,并适用于页面加载后呈现的元素。
例如:
1 2 3 | $(document).on("click", $(selector), function() { // Your code here }); |
注意"main"类,例如,元素被放置在
1 2 3 4 5 6 7 8 9 10 11 12 13 | <ul class="select"> <li> First </li> <li> Second </li> </ul> |
在上述场景中,jquery将监视的主要对象是"container"。
然后在容器下基本上有元素名,如
1 2 3 4 5 | $(document).ready(function(e) { $('.container').on( 'click',".select", function(e) { alert("CLICKED"); }); }); |
当使用
As of jQuery 1.8, any jQuery instance method (a method of
jQuery.fn ) can be used as a property of the object passed to the
second parameter:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function handleDynamicElementEvent(event) { console.log(event.type, this.value) } // create and attach event to dynamic element jQuery("<select>", { html: $.map(Array(3), function(_, index) { return new Option(index, index) }), on: { change: handleDynamicElementEvent } }) .appendTo("body"); |
1 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> |
你可以使用
1 2 3 | $('.buttons').on('click', 'button', function(){ // your magic goes here }); |
或
1 2 3 | $('.buttons').delegate('button', 'click', function() { // your magic goes here }); |
这两种方法是等效的,但参数顺序不同。
参见:jquery委托事件
这就是动态创建的元素不响应单击的原因:
1 2 3 4 5 6 7 8 9 10 11 | var body = $("body"); var btns = $("button"); var btnB = $("<button>B</button>"); // `<button>B</button>` is not yet in the document. // Thus, `$("button")` gives `[<button>A</button>]`. // Only `<button>A</button>` gets a click listener. btns.on("click", function () { console.log(this); }); // Too late for `<button>B</button>`... body.append(btnB); |
1 2 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> <button>A</button> |
作为解决方法,您必须倾听所有单击并检查源元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var body = $("body"); var btnB = $("<button>B</button>"); var btnC = $("<button>C</button>"); // Listen to all clicks and // check if the source element // is a `<button></button>`. body.on("click", function (ev) { if ($(ev.target).is("button")) { console.log(ev.target); } }); // Now you can add any number // of `<button></button>`. body.append(btnB); body.append(btnC); |
1 2 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> <button>A</button> |
这被称为"事件委托"。好消息,这是jquery中内置的特性:-)
1 2 3 4 5 6 | var i = 11; var body = $("body"); body.on("click","button", function () { var letter = (i++).toString(36).toUpperCase(); body.append($("<button>" + letter +"</button>")); }); |
1 2 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> <button>A</button> |
在事件绑定时存在的任何父节点,如果页动态创建具有类名按钮的元素,则将事件绑定到已经存在的父节点。
1 2 3 4 5 6 7 8 9 10 11 12 | $(document).ready(function(){ //Particular Parent chield click $(".buttons").on("click","button",function(){ alert("Clicked"); }); //Dynamic event bind on button class $(document).on("click",".button",function(){ alert("Dymamic Clicked"); }); $("input").addClass("button"); }); |
1 2 3 4 5 6 7 8 9 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"> <input type="button" value="1"> <button>2</button> <input type="text"> <button>3</button> <input type="button" value="5"> <button>6</button> |
试试这样——
1 | $(document).on( 'click', '.click-activity', function () { ... }); |
这是通过事件委托来完成的。事件将在包装类元素上绑定,但将委托给选择器类元素。这就是它的运作方式。
1 2 3 | $('.wrapper-class').on("click", '.selector-class', function() { // Your code here }); |
注:
包装类元素可以是任何Ex.文件,体或包装。包装应该已经存在。然而,
使用jquery http://api.jquery.com/on/的
从1.9版起,删除了
将事件绑定到已存在的父级:
1 2 3 | $(document).on("click","selector", function() { // Your code here }); |
创建元素和绑定事件的另一个灵活解决方案(源)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // creating a dynamic element (container div) var $div = $("", {id: 'myid1', class: 'myclass'}); //creating a dynamic button var $btn = $("<button>", { type: 'button', text: 'Click me', class: 'btn' }); // binding the event $btn.click(function () { //for mouseover--> $btn.on('mouseover', function () { console.log('clicked'); }); // append dynamic button to the dynamic container $div.append($btn); // add the dynamically created element(s) to a static element $("#box").append($div); |
注意:这将为每个元素创建一个事件处理程序实例(在循环中使用时可能会影响性能)
我更喜欢以模块化的函数方式部署事件侦听器,而不是编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var iterations = 4; var button; var body = document.querySelector("body"); for (var i = 0; i < iterations; i++) { button = document.createElement("button"); button.classList.add("my-button"); button.appendChild(document.createTextNode(i)); button.addEventListener("click", myButtonWasClicked); body.appendChild(button); } function myButtonWasClicked(e) { console.log(e.target); //access to this specific button } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <html> <head> HTML Document <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js"> </head> <body> Hello World jQuery(document).ready(function($){ $(document).on('mouseover', '#hover-id', function(){ $(this).css('color','yellowgreen'); }); $(document).on('mouseout', '#hover-id', function(){ $(this).css('color','black'); }); }); </body> </html> |
我正在寻找一种解决方案,让
as on()使用附加事件的技巧,以便在我遇到的事件上创建一个假的取消绑定:
1 2 3 4 5 6 | const sendAction = function(e){ ... } // bind the click $('body').on('click', 'button.send', sendAction ); // unbind the click $('body').on('click', 'button.send', function(){} ); |