在 javascript 中将事件附加到动态元素

我试图将 html 数据动态地插入到动态创建的列表中,但是当我试图为动态创建的按钮附加 onclick 事件时,事件没有被触发。如果能解决这个问题,我将不胜感激。

Javascript 代码:

document.addEventListener('DOMContentLoaded', function () {
document.getElementById('btnSubmit').addEventListener('click', function () {
var name = document.getElementById('txtName').value;
var mobile = document.getElementById('txtMobile').value;
var html = '<ul>';
for (i = 0; i < 5; i++) {
html = html + '<li>' + name + i + '</li>';
}
html = html + '</ul>';


html = html + '<input type="button" value="prepend" id="btnPrepend" />';
document.getElementsByTagName('form')[0].insertAdjacentHTML('afterend', html);
});


document.getElementById('btnPrepend').addEventListener('click', function () {
var html = '<li>Prepending data</li>';
document.getElementsByTagName('ul')[0].insertAdjacentHTML('afterbegin', html);
});
});

HTML 代码:

<form>
<div class="control">
<label>Name</label>
<input id="txtName" name="txtName" type="text" />
</div>
<div class="control">
<label>Mobile</label>
<input id="txtMobile" type="text" />
</div>
<div class="control">
<input id="btnSubmit" type="button" value="submit" />
</div>
</form>
254086 次浏览

你可以做类似的事情:

// Get the parent to attatch the element into
var parent = document.getElementsByTagName("ul")[0];


// Create element with random id
var element = document.createElement("li");
element.id = "li-"+Math.floor(Math.random()*9999);


// Add event listener
element.addEventListener("click", EVENT_FN);


// Add to parent
parent.appendChild(element);

必须在插入元素之后附加事件,比如不在 document上附加全局事件,而是在插入的元素上附加特定事件。

例如:。

document.getElementById('form').addEventListener('submit', function(e) {
e.preventDefault();
var name = document.getElementById('txtName').value;
var idElement = 'btnPrepend';
var html = `
<ul>
<li>${name}</li>
</ul>
<input type="button" value="prepend" id="${idElement}" />
`;
/* Insert the html into your DOM */
insertHTML('form', html);
/* Add an event listener after insert html */
addEvent(idElement);
});


const insertHTML = (tag = 'form', html, position = 'afterend', index = 0) => {
document.getElementsByTagName(tag)[index].insertAdjacentHTML(position, html);
}
const addEvent = (id, event = 'click') => {
document.getElementById(id).addEventListener(event, function() {
insertHTML('ul', '<li>Prepending data</li>', 'afterbegin')
});
}
<form id="form">
<div>
<label for="txtName">Name</label>
<input id="txtName" name="txtName" type="text" />
</div>
<input type="submit" value="submit" />
</form>

有一个解决办法是捕获对 document.body的点击,然后检查事件目标。

document.body.addEventListener( 'click', function ( event ) {
if( event.target.id == 'btnSubmit' ) {
someFunc();
};
} );

这是因为您的元素是动态创建的,所以它以后会附加到 DOM,但是您的 addEventListener调用已经在过去发生过了。 您应该使用 活动代表团来处理事件。

document.addEventListener("click", function(e){
const target = e.target.closest("#btnPrepend"); // Or any other selector.


if(target){
// Do something with `target`.
}
});

closest 确保单击发生在目标元素内部的 任何地方或目标元素本身的 。 这是有用的,例如,如果你有一个 <button id="btnPrepend"><i class="icon">+</i> prepend</button>而不是你的 <input id="btnPrepend"/>,你点击了 <i class="icon">+</i>

JQuery 让它变得更容易:

$(document).on("click", "#btnPrepend", function(){
// Do something with `$(this)`.
});

这是 关于活动授权的文章

var __ = function(){
this.context  = [];
var self = this;
this.selector = function( _elem, _sel ){
return _elem.querySelectorAll( _sel );
}
this.on = function( _event, _element, _function ){
this.context = self.selector( document, _element );
document.addEventListener( _event, function(e){
var elem = e.target;
while ( elem != null ) {
if( "#"+elem.id == _element || self.isClass( elem, _element ) || self.elemEqal( elem ) ){
_function( e, elem );
}
elem = elem.parentElement;
}
}, false );
};


this.isClass = function( _elem, _class ){
var names = _elem.className.trim().split(" ");
for( this.it = 0; this.it < names.length; this.it++ ){
names[this.it] = "."+names[this.it];
}
return names.indexOf( _class ) != -1 ? true : false;
};


this.elemEqal = function( _elem ){
var flg = false;
for( this.it = 0; this.it < this.context.length;  this.it++ ){
if( this.context[this.it] === _elem && !flg ){
flg = true;
}
}
return flg;
};


}


function _( _sel_string ){
var new_selc = new __( _sel_string );
return new_selc;
}

现在您可以注册事件,例如,

_( document ).on( "click", "#brnPrepend", function( _event, _element ){
console.log( _event );
console.log( _element );
// Todo


});

浏览器支持

Chrome-4.0,Edge-9.0,Firefox-3.5 Safari-3.2,Opera-10.0及以上版本

我已经创建了一个小型库来帮助这个: GitHub 上的库源代码

<script src="dynamicListener.min.js"></script>
<script>
// Any `li` or element with class `.myClass` will trigger the callback,
// even elements created dynamically after the event listener was created.
addDynamicEventListener(document.body, 'click', '.myClass, li', function (e) {
console.log('Clicked', e.target.innerText);
});
</script>

其功能类似于 jQuery.on ()。

该库使用 匹配()方法针对给定的选择器测试目标元素。当触发事件时,只有当目标元素与给定的选择器匹配时才调用回调。

我做了个简单的函数。

_case函数不仅允许您获取目标,还允许您获取绑定事件的父元素。

回调函数返回包含目标(evt.target)和匹配选择器(this)的父元素的事件。在这里,您可以在单击元素后执行所需的操作。

我还没有决定哪个更好,if-else还是 switch

var _case = function(evt, selector, cb) {
var _this = evt.target.closest(selector);
if (_this && _this.nodeType) {
cb.call(_this, evt);
return true;
} else { return false; }
}


document.getElementById('ifelse').addEventListener('click', function(evt) {
if (_case(evt, '.parent1', function(evt) {
console.log('1: ', this, evt.target);
})) return false;


if (_case(evt, '.parent2', function(evt) {
console.log('2: ', this, evt.target);
})) return false;


console.log('ifelse: ', this);
})




document.getElementById('switch').addEventListener('click', function(evt) {
switch (true) {
case _case(evt, '.parent3', function(evt) {
console.log('3: ', this, evt.target);
}): break;
case _case(evt, '.parent4', function(evt) {
console.log('4: ', this, evt.target);
}): break;
default:
console.log('switch: ', this);
break;
}
})
#ifelse {
background: red;
height: 100px;
}
#switch {
background: yellow;
height: 100px;
}
<div id="ifelse">
<div class="parent1">
<div class="child1">Click me 1!</div>
</div>
<div class="parent2">
<div class="child2">Click me 2!</div>
</div>
</div>


<div id="switch">
<div class="parent3">
<div class="child3">Click me 3!</div>
</div>
<div class="parent4">
<div class="child4">Click me 4!</div>
</div>
</div>

希望能有帮助!

区别在于如何在 DOM 中创建和追加元素。

如果通过 document.createElement创建元素,则添加一个事件侦听器,并将其附加到 DOM。你的活动会火起来的。

如果您将一个元素创建为如下所示的字符串: html + = “ < li > test ”’,那么从技术上讲,这个元素只是一个字符串。字符串不能有事件侦听器。

一种解决方案是使用 document.createElement创建每个元素,然后将它们直接添加到 DOM 元素中。

// Sample
let li = document.createElement('li')
document.querySelector('ul').appendChild(li)

我知道这个主题太老了,但是我给自己一些时间来创建一个非常有用的代码,它使用纯 JAVASCRIPT工作得很好,也很容易。 下面是一个简单示例的代码:

String.prototype.addEventListener=function(eventHandler, functionToDo){
let selector=this;
document.body.addEventListener(eventHandler, function(e){
e=(e||window.event);
e.preventDefault();
const path=e.path;
path.forEach(function(elem){
const selectorsArray=document.querySelectorAll(selector);
selectorsArray.forEach(function(slt){
if(slt==elem){
if(typeof functionToDo=="function") functionToDo(el=slt, e=e);
}
});
});
});
}


// And here is how we can use it actually !


"input[type='number']".addEventListener("click", function(element, e){
console.log( e ); // Console log the value of the current number input
});
<input type="number" value="25">
<br>
<input type="number" value="15">
<br><br>
<button onclick="addDynamicInput()">Add a Dynamic Input</button>
<script type="text/javascript">
function addDynamicInput(){
const inpt=document.createElement("input");
inpt.type="number";
inpt.value=Math.floor(Math.random()*30+1);
document.body.prepend(inpt);
}
</script>

我发现通过 Jillykate发布的解决方案是可行的,但是只有当目标元素是最嵌套的时候。如果不是这种情况,可以通过迭代父元素来纠正。

function on_window_click(event)
{
let e = event.target;


while (e !== null)
{
// --- Handle clicks here, e.g. ---
if (e.getAttribute(`data-say_hello`))
{
console.log("Hello, world!");
}


e = e.parentElement;
}
}


window.addEventListener("click", on_window_click);

还要注意,我们可以通过任何属性处理事件,或者在任何级别附加侦听器。上面的代码使用一个自定义属性和 window。我怀疑不同的方法之间有任何语用上的区别。

这是我想到的另一个解决办法。我发现这比事件目标更容易处理,因为他们不会开火,如果一个孩子被点击。该方法是设置事件侦听器,并在向文档添加新元素后重置它们:

function listen() {
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener("click", function(){
console.log("Hello World");
});
});
}


listen();


document.body.innerHTML += "<p class='btn'>Click Here 2.0 .</p>";


listen();
<!DOCTYPE html>
<html>
<body>


<p class='btn'>Click Here.</p>


</body>
</html>

编辑: 要避免同一事件的堆叠侦听器,请参见: < a href = “ https://stackoverflow. com/a/47330239/14988173”> 解答

First of all add the dynamic class to the dynamically created inputboxes
var ele = document.createElement('textarea');
ele.className = "css-class-name"; // set the CSS class
ele.setAttribute('type', 'textarea');
ele.setAttribute('value', '');
ele.setAttribute("id", `row${rcount}_${c}`);
then do the following
const btns = document.querySelectorAll('.css-class-name');
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('keyup', function (e) {
console.log(e.target.id);
let textValues = $(`#${e.target.id}`).val()
console.log("=============values =====", textValues)
//on key press take id and set value of that id what i am inputting.
});
}

下面是一个利用 Element.match的可重用函数:

function delegate_event(event_type, ancestor_element, target_element_selector, listener_function)
{
ancestor_element.addEventListener(event_type, function(event)
{
if (event.target && event.target.matches && event.target.matches(target_element_selector))
{
(listener_function)(event);
}
});
}

下面是如何使用它来点击事件:

delegate_event('click', document, '.alert-button', your_function_here);

我喜欢 @ Pikamander2解决方案,因为它不涉及对文档或主体的事件绑定(有一天你会醒来,每次单击文档都会触发几十个事件处理程序...)。

这里是一个改进的 Pikamander2解决方案。

如果动态添加的子元素本身是带子元素的 dom 元素(例如: <button><u>label</u></button>,则 e.target可以返回 <u>元素。因此,你可以使用:

function delegateEvent( eventType, ancestorElem, childSelector, eventHandler ) {


// Cancel if ancestorElem does not exists
if( ! ancestorElem || ( typeof ancestorElem === 'string' && ! ( ancestorElem = document.querySelector( ancestorElem ) ) ) ) {
return
}


ancestorElem.addEventListener( eventType, e => {
if( e.target && e.target.closest && e.target.closest( childSelector ) ) {
( eventHandler )( e )
}
} )


}

我还添加了一个代码片段,使函数接受祖先的选择器,而不是只接受元素

这是一个古老的问题-但我花了很多时间与这个问题。也许我的方法能帮到别人。

上下文: 将事件侦听器附加到从 Ajax 响应动态创建的元素。通过单击或键盘导航进行选择: 在这两种情况下,调用相同的函数。

第一行成功了,第二行不允许我点击这个项目:

item.addEventListener("mouseover", this.mouseOver.bind(this) )
item.addEventListener("click", this.clickedItem.bind(this) )

然而,这种做法继续发挥作用:

item.click();

(建议添加了 click 事件,并调用函数-但是鼠标没有发送 click 事件)

解决办法是改变:

item.addEventListener("click", this.clickedItem.bind(this) )

回到这里:

item.addEventListener("mousedown", this.clickedItem.bind(this) )

我看到在旧的 SO 消息,建议 <div>s不响应鼠标点击事件-但所有的文档我阅读矛盾。

我不知道这是怎么回事。