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

时间:2016-01-20 09:26:07

标签: 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>

11 个答案:

答案 0 :(得分:80)

这是因为你的元素是动态创建的,你应该event delegation来处理事件。

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

jquery让它变得更容易:

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

以下是您可以阅读的有关事件委派event delegation article

的文章

答案 1 :(得分:9)

您需要在创建元素后附加事件。喜欢:

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

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

答案 2 :(得分:9)

通过捕获document.body上的点击然后检查事件目标,有一种解决方法。

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

答案 3 :(得分:2)

你可以做类似的事情:

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

答案 4 :(得分:1)

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及更高版本

答案 5 :(得分:1)

我创建了一个小型图书馆来帮助您:Library source on GitHub

Total 40 (delta 14), reused 0 (delta 0)
error: RPC failed; curl 56 SSLRead() return error -9806
fatal: the remote end hung up unexpectedly
fatal: the remote end hung up unexpectedly
Everything up-to-date

功能类似于jQuery.on()。

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

答案 6 :(得分:1)

我知道这个话题太老了,但是我花了几分钟时间来创建一个非常有用的代码,使用纯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>

答案 7 :(得分:1)

这是我想出的另一个解决方案。我发现与事件目标相比,这更容易处理,因为如果单击子项,它们不会触发。方法是设置事件监听器并在向文档追加新元素后重置它们:

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>

编辑: 为避免同一事件的堆叠侦听器,请参阅:Answer

答案 8 :(得分:0)

我为此做了一个简单的功能。

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

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

我还不确定if-elseswitch哪个更好

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

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

  if (_case(evt, '.parent2', function(evt) {
      console.log('2: ', evt._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: ', evt._this, evt.target);
    }): break;
    case _case(evt, '.parent4', function(evt) {
      console.log('4: ', evt._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>

希望有帮助!

答案 9 :(得分:0)

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

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

如果您将元素创建为像这样的字符串:html + =“

  • test
  • ”`,从技术上讲,元素只是一个字符串。字符串不能具有事件侦听器。

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

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

    答案 10 :(得分:0)

    我发现 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。我怀疑各种方法之间是否存在实用上的差异。