Javascript 如何在DOM[no jQuery]中尚未包含的元素上添加事件侦听器?

Javascript 如何在DOM[no jQuery]中尚未包含的元素上添加事件侦听器?,javascript,html,Javascript,Html,我想将事件侦听器(调用函数)附加到DOM中尚未出现的按钮。我不想在HTML中使用内联调用,我该怎么做 到目前为止,我可以通过创建一个全局事件监听器来实现我想要的,该监听器检查单击的元素是否具有特定的Id。但是我发现这个解决方案是肮脏的,不是最优的 const messageForm = document.querySelector("#message-form") const messageTextarea = document.querySelector("#message-textarea"

我想将事件侦听器(调用函数)附加到DOM中尚未出现的按钮。我不想在HTML中使用内联调用,我该怎么做

到目前为止,我可以通过创建一个
全局事件监听器来实现我想要的,该监听器检查单击的元素是否具有特定的Id。但是我发现这个解决方案是肮脏的,不是最优的

const messageForm = document.querySelector("#message-form")
const messageTextarea = document.querySelector("#message-textarea");
const messageList = document.querySelector("#message-list");
const messageEmpty = document.querySelector("#message-empty");
let messageNumber = 0;

const messageFormatted = messageText => {
  return `
  <li class="message-item">
    <img class="message-avatar" src="./icons/boy.png" alt="Username">
      <article class="message-content">
        <p class="author">Ernesto Campese</p>
        <p class="message">${messageText}</p>
        <p class="datetime">A moment ago</p>
      </article>
      <div class="message-actions">
        <img id="message-edit" class="action-button" src="./icons/edit.png" alt="" width="22" height="22">
        <img id="message-delete" class="action-button" src="./icons/delete.png" alt="" width="22" height="22">
      </div>
  </li>
  `;
}

document.addEventListener("click", (e) => {
  if (e.target.id === "message-delete") {
    e.target.parentNode.parentNode.remove();
    messageNumber--;
    messageEmptyCheck();
  }
})

messageForm.addEventListener("submit", (e) => {
  e.preventDefault();
  if (messageTextarea.value !== "") {
    messageList.insertAdjacentHTML("beforeend", messageFormatted(messageTextarea.value));
    messageTextarea.value = null;
    messageTextarea.focus();
    messageNumber++;
    messageEmptyCheck();
  }
});

希望我说得够清楚,谢谢你们

你在正确的轨道上。识别特征不必是
id
,它可以是关于元素的任何东西-类是一种常见的方法

有三种DOM方法可以帮助实现灵活:

  • -从您调用它的元素开始,它查找与给定CSS选择器匹配的最近祖先
  • -检查节点是否包含其他节点
  • -检查调用它的元素是否与给定的CSS选择器匹配
例如,当前处理程序要求按钮是单击的元素(
event.target
)。这对于您的
img
用例来说很好,但是如果它是一个
按钮,里面有一个
img
,会怎么样?然后,
event.target
可能是
img
按钮,具体取决于用户单击的位置<代码>最近的
包含以下帮助:

document.addEventListener("click", (e) => {
  const button = e.target.closest("#message-delete");
  if (button) {
    button.closest("li").remove();
    messageNumber--;
    messageEmptyCheck();
  }
})
您还需要将事件挂接到最近的容器上。有时候,你会被
document
document.body
所困扰。但通常情况下,你可以做得更好。例如,当在表格单元格中的按钮上侦听按钮单击时,您可以在
表格
t正文
/
而不是文档级别侦听。这就是
contains
进入等式的地方,它确保了
最近的
不会在文档树上走得太远:

document.querySelector("selector-for-the-table").addEventListener("click", (e) => {
  const button = e.target.closest("#message-delete");
  if (button && e.currentTarget.contains(button)) {
  //        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    button.closest("li").remove();
    messageNumber--;
    messageEmptyCheck();
  }
})

在您的情况下,对
#message delete
的搜索不太可能超出包含元素,因此您可能不需要该位,但有时也会发生这种情况,因此您希望
包含
检查。

如果您真的想将事件侦听器添加到该元素本身,那么我认为您可能需要尝试使用MutationObserver-

您可以通过传递config for childList、subtree来观察事件,并在事件上检查您要查找的元素是否已添加或存在。如果您发现可以添加事件侦听器

你可能想看看以下文章-


我希望这会有所帮助。

您可以将HTML字符串解析为JS中的
文档
,然后将事件侦听器添加到该元素中

这样就得到了模板文本字符串

const messageFormatted = messageText => {
  return `
  <li class="message-item">
    <img class="message-avatar" src="./icons/boy.png" alt="Username">
      <article class="message-content">
        <p class="author">Ernesto Campese</p>
        <p class="message">${messageText}</p>
        <p class="datetime">A moment ago</p>
      </article>
      <div class="message-actions">
        <img id="message-edit" class="action-button" src="./icons/edit.png" alt="" width="22" height="22">
        <img id="message-delete" class="action-button" src="./icons/delete.png" alt="" width="22" height="22">
      </div>
  </li>
  `;
}
这个文档的工作原理与页面中的文档类似,它只是一个新文档,目前只存在于JS内存中。将您的
string
作为参数提供给
parseStringToHTML
以创建HTML

const message = messageFormatted('This is the message'); // Example message
const messageHTML = parseStringToHTML(message); // Returns a document object with all the features a document object has.
因此,既然您的
字符串
是一个
文档
,您可以在其上使用类似
getElementById
querySelector
等方法。但是首先必须选择所需的元素

const messageDeleteButton = messageHTML.querySelector("#message-delete");
请注意,我使用了
messageHTML
而不是
document
。在这个场景中,
messageHTML
是一个
文档
,因此我们可以在其中查询。现在您已经在这个
文档中找到了您的元素
,您可以向其中添加一个事件侦听器

messageDeleteButton.addEventListener("click", (e) => {
    e.parentNode.parentNode.remove();
});
好的,现在已经添加了事件侦听器。您现在需要做的就是将
messageHTML
中所需的HTML附加到页面的
文档中。HTML可以在
messageHTML.body
属性中找到

现在,不要使用
insertAdjacentHTML
在您选择的位置插入元素。要附加的元素是
  • ,它将是
    messageHTML.body
    属性的
    正文中的
    firstElementChild

    因此,在表单的
    submit
    事件侦听器中,更改以下行:

    messageList.insertAdjacentHTML("beforeend", messageFormatted(messageTextarea.value));
    
    以上我已经解释过了

    // Create string
    const message = messageFormatted(messageTextarea.value);
    
    // String to document
    const messageHTML = parseStringToHTML(message);
    
    // Select delete element.
    const messageDeleteButton = messageHTML.querySelector("#message-delete");
    
    // Add event listener to delete element.
    messageDeleteButton.addEventListener("click", (e) => {   
        e.parentNode.parentNode.remove();
    });
    
    // Append the <li> element to the messageList.
    messageList.insertAdjacentElement("beforeend", messageHTML.body.firstElementChild); 
    
    //创建字符串
    const message=messageFormatted(messageTextarea.value);
    //字符串到文档
    const messageHTML=parseStringToHTML(消息);
    //选择删除元素。
    const messageDeleteButton=messageHTML.querySelector(“#message delete”);
    //添加事件侦听器以删除元素。
    messageDeleteButton.addEventListener(“单击”,(e)=>{
    e、 parentNode.parentNode.remove();
    });
    //将
  • 元素附加到messageList。 insertAdjacentElement(“beforeend”,messageHTML.body.firstElementChild);
  • 不要忘记在代码中包含
    parseStringToHTML
    函数。我知道这是一个很大的工作,所以如果你有任何问题,请问

    我希望这能帮助你


    注意我发现事件委派(全局事件侦听器)不是您想要做的事情,尽管正如其他人所说,它比其他方法(甚至是我自己的答案)更高效、更容易实现。它还可以解决监听您在列表中添加甚至删除的元素的问题。您甚至可以在
    元素上设置它,如T.J.Crowder建议将侦听器附加到文档级别而不是元素level@ImmortalDude-请看问题中的代码。让我这样说,如果您将这样的文档与多个事件侦听器连接起来,你迟早会遇到麻烦的。图像中有一个消息删除按钮、消息投票按钮、消息等等。这并不是批评您,而是针对引擎在文档或容器中的每次单击
    messageList.insertAdjacentHTML("beforeend", messageFormatted(messageTextarea.value));
    
    // Create string
    const message = messageFormatted(messageTextarea.value);
    
    // String to document
    const messageHTML = parseStringToHTML(message);
    
    // Select delete element.
    const messageDeleteButton = messageHTML.querySelector("#message-delete");
    
    // Add event listener to delete element.
    messageDeleteButton.addEventListener("click", (e) => {   
        e.parentNode.parentNode.remove();
    });
    
    // Append the <li> element to the messageList.
    messageList.insertAdjacentElement("beforeend", messageHTML.body.firstElementChild);