【问题标题】:Cannot use addEventListener() on a createElement() (a button) after displaying it in the DOM (in javascript)在 DOM(在 javascript 中)显示后,无法在 createElement()(按钮)上使用 addEventListener()
【发布时间】:2021-02-08 19:52:46
【问题描述】:

我最近正在创建一个 Javascript 框架,但我遇到了两个我完全不理解的问题。当我在 Javascript 中使用createElement() 创建一个新按钮时,我不能同时将它放在多个元素中而不杀死“点击”事件(如果这是一个id,它可以工作)。

(注意:"button.onclick = function()" 也不起作用)

这是代码:(我不想使用任何库)

function createButton() {
    var button = document.createElement("button");
    button.innerHTML = "YOOOO";
    button.style.backgroundColor = "red";
    button.style.color = "white";

    // Problem Two : If I click on the button, nothing happends
    button.addEventListener("click", function(e) {
        alert(e.target);
    }, false);

    var clas = document.getElementsByClassName("test");
    Array.from(clas).forEach(element => {
        element.appendChild(button);
        element.innerHTML += ""; // First problem : If I don't do this, the button does not appear in the first div. I have no idea why !
    });
}
createButton();
 body {
    margin: 0;
    padding: 0;
    display:flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: rgba(30, 30, 30, 0.2);
}

button {
    cursor: pointer;
    width: 80px;
    height: 50px;
    padding: 10px;
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>bug</title>
</head>

<body>

<div class="test" id="1" style="padding: 50px;">
    <span>1</span>
</div>
<div class="test" id="2" style="padding: 50px;">
    <span>2</span>
</div>

</body>
</html>

【问题讨论】:

    标签: javascript html addeventlistener createelement


    【解决方案1】:

    我强烈建议你委托和克隆

    我想我几天前已经为你发布了这个答案

    function createButton() {
      const button = document.createElement("button");
      button.classList.add("redwhite");
      button.innerHTML = "YOOOO";
      [...document.querySelectorAll(".test")].forEach(element => {
        element.appendChild(button.cloneNode(true));
      });
    }
    createButton();
    document.getElementById("container").addEventListener("click", function(e) {
      const tgt = e.target;
      if (tgt.classList.contains("redwhite")) {
        console.log(tgt.closest("div").id)
      }  
    })
    body {
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background-color: rgba(30, 30, 30, 0.2);
    }
    
    button {
      cursor: pointer;
      width: 80px;
      height: 50px;
      padding: 10px;
    }
    
    .redwhite {
      background-color: red;
      color: white;
    }
    <div id="container">
      <div class="test" id="1" style="padding: 50px;">
        <span>1</span>
      </div>
      <div class="test" id="2" style="padding: 50px;">
        <span>2</span>
      </div>
    </div>

    【讨论】:

    • 我会调查的,谢谢。这是我在stackoverflow上的第一篇文章,我希望我的问题没有在我之前发布过我的其他人,我什么也没找到
    【解决方案2】:

    您的按钮是单个实例,并且重复调用

    element.appendChild(button);
    

    只是在 DOM 中反复移动它。

    您随后致电

    element.innerHTML += "";
    

    从 DOM 中删除该引用,而是从其 outerHTML 创建一个新的 button。这也是您添加的事件侦听器丢失的地方。

    如果您需要多个按钮,您还需要创建多个按钮。

    【讨论】:

      【解决方案3】:

      有2个问题:

      • element.innerHTML += "";,其中element 指的是按钮的父级,将强制父级从其HTML 字符串重新解析其内容,从而破坏子元素上的任何现有处理程序。监听器所附加的元素将从 DOM 中移除并替换为不同的元素;新的没有监听器。

      • 当您执行appendChild 时,如果要附加的元素已经存在于 DOM 中,则在附加到新位置之前,它将从先前存在的位置移除。由于您只执行一次document.createElement('button'),而没有innerHTML += '',因此当附加到第二个按钮时,该按钮将从其第一个位置移除。

      改为在循环内创建按钮,这两个问题都解决了。

      function createButton() {
        var clas = document.getElementsByClassName("test");
        Array.from(clas).forEach(element => {
      
          var button = document.createElement("button");
          button.innerHTML = "YOOOO";
          button.style.backgroundColor = "red";
          button.style.color = "white";
      
          // Problem Two : If I click on the button, nothing happends
          button.addEventListener("click", function(e) {
            alert(e.target);
          }, false);
          element.appendChild(button);
      
        });
      }
      createButton();
      body {
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background-color: rgba(30, 30, 30, 0.2);
      }
      
      button {
        cursor: pointer;
        width: 80px;
        height: 50px;
        padding: 10px;
      }
      <div class="test" id="1" style="padding: 50px;">
        <span>1</span>
      </div>
      <div class="test" id="2" style="padding: 50px;">
        <span>2</span>
      </div>

      或者,让代码更漂亮一点:

      function createButton() {
        for (const parent of document.querySelectorAll('.test')) {
          const button = parent.appendChild(document.createElement("button"));
          button.textContent = "YOOOO";
          button.style.backgroundColor = "red";
          button.style.color = "white";
          button.addEventListener("click", function(e) {
            console.log(e.target);
          });
        }
      }
      createButton();
      body {
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background-color: rgba(30, 30, 30, 0.2);
      }
      
      button {
        cursor: pointer;
        width: 80px;
        height: 50px;
        padding: 10px;
      }
      <div class="test" id="1" style="padding: 50px;">
        <span>1</span>
      </div>
      <div class="test" id="2" style="padding: 50px;">
        <span>2</span>
      </div>

      【讨论】:

      • 首先创建并附加按钮,然后才改变外观和文本内容,这在性能方面是一个非常糟糕的主意。
      • 这里不是性能关键的紧密循环,所以应该不是问题,对吧?我更喜欢简洁的版本,它似乎在这里。重绘也仅在所有同步 JS 完成后才会发生,IIRC
      • 谢谢!它解决了我的问题,我会做类似的事情
      猜你喜欢
      • 2017-07-14
      • 2021-06-10
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 2017-05-10
      • 2011-01-11
      • 2017-01-18
      • 1970-01-01
      相关资源
      最近更新 更多