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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34896106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:00:51  来源:igfitidea点击:

Attach event to dynamic elements in javascript

javascript

提问by Manju

I'm trying to insert html data dynamically to a list that is dynamically created, but when i try to attach an onclick event for the button that is dynamically created the event is not firing. Solution would be really appreciated.

我正在尝试将 html 数据动态插入到动态创建的列表中,但是当我尝试为动态创建的按钮附加 onclick 事件时,该事件不会触发。解决方案将不胜感激。

Javascript code:

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 Code:

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>

回答by jilykate

This is due to the fact that your element is dynamically created. You should use event delegationto handle the event.

这是因为您的元素是动态创建的。您应该使用事件委托来处理事件。

 document.addEventListener('click',function(e){
    if(e.target && e.target.id== 'brnPrepend'){
          //do something
     }
 });

jquery makes it easier:

jquery 使它更容易:

 $(document).on('click','#btnPrepend',function(){//do something})

Here is an article about event delegation event delegation article

这是一篇关于事件委托事件委托的文章

回答by Manasov Daniel

There is a workaround by capturing clicks on document.bodyand then checking event target.

有一种解决方法是捕获点击document.body然后检查事件目标。

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

回答by R3tep

You must attach the event after insert elements, like that you don't attach a global event on your documentbut a specific event on the inserted elements.

您必须在插入元素之后附加事件,就像您不在插入元素上附加全局事件,document而是在插入元素上附加特定事件一样。

e.g.

例如

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>

回答by Richard

The difference is in how you create and append elements in the DOM.

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

If you create an element via document.createElement, add an event listener, and append it to the DOM. Your events will fire.

如果您通过 来创建元素document.createElement,请添加一个事件侦听器,并将其附加到 DOM。你的事件会触发。

If you create an element as a string like this: html += "<li>test</li>"`, the elment is technically just a string. Strings cannot have event listeners.

如果您将元素创建为这样的字符串:html += "<li>test</li>"`,则元素在技术上只是一个字符串。字符串不能有事件监听器。

One solution is to create each element with document.createElementand then add those to a DOM element directly.

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

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

回答by PRDeving

You can do something similar to this:

你可以做类似的事情:

// 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);

回答by paranjothi

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;
    }

Now you can register event like,

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

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

  });

Browser Support

浏览器支持

chrome - 4.0, Edge - 9.0, Firefox - 3.5 Safari - 3.2, Opera - 10.0 and above

chrome - 4.0,Edge - 9.0,Firefox - 3.5 Safari - 3.2,Opera - 10.0 及更高版本

回答by XCS

I have created a small library to help with this: Library source on GitHub

我创建了一个小型库来帮助解决这个问题: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>

The functionality is similar to jQuery.on().

功能类似于 jQuery.on()。

The library uses the Element.matches()method to test the target element against the given selector. When an event is triggered the callback is only called if the target element matches the selector given.

该库使用Element.matches()方法根据给定的选择器测试目标元素。当一个事件被触发时,只有当目标元素与给定的选择器匹配时才会调用回调。

回答by ssten

I've made a simple function for this.

我为此做了一个简单的函数。

The _casefunction allows you to not only get the target, but also get the parent element where you bind the event on.

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

The callback function returns the event which holds the target (evt.target) and the parent element matching the selector (this). Here you can do the stuff you need after the element is clicked.

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

I've not yet decided which is better, the if-elseor the switch

我还没有决定哪个更好,那个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>

Hope it helps!

希望能帮助到你!

回答by Adnane Ar

I know that the topic is too old but I gave myself some minutes to create a very useful code that works fine and very easy using pure JAVASCRIPT. Here is the code with a simple example:

我知道这个话题太老了,但我给了自己一些时间来创建一个非常有用的代码,使用 pure 可以正常工作并且非常容易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>