繁体   English   中英

使用 JavaScript 添加元素时检测 HTML 变化

[英]Detecting HTML changes when adding elements with JavaScript

我遇到了点击事件的问题。

这是代码:

for (const button of itemClick) button.addEventListener("click", function() {
    clickCount++;
    if (clickCount == 1) {
        value1 = button.getAttribute("value");

    }
    if (clickCount >= 2) {
        value2 = button.getAttribute("value");
        clickCount = 0;
        onItemClick();
    }
});

itemClick 引用了一个名为 item 的文档类名变量

因此,如果我在该项目上单击两次,它应该添加第二个项目,但单击由 JavaScript 创建的项目不想工作,所以我必须以某种方式让 JavaScript 知道 Z4C4AD5FCA2E7A3F74DBB1CED0031 上它也改变了有效果,但我不知道该怎么做,也找不到任何信息。

我在 HTML 中添加元素,如下所示:

let itemDiv = document.createElement("div");
            let imageDiv = document.createElement("div");
            let imgEl = document.createElement("img");
            let itHeading = document.createElement("h6");

            let itemslistcontent = document.getElementById("items");

            itemslistcontent.appendChild(itemDiv);
            itemDiv.appendChild(imageDiv);
            imageDiv.appendChild(imgEl);
            itemDiv.appendChild(itHeading);
            itemDiv.classList.add("item");
            itemDiv.setAttribute("value", prop);
            itHeading.innerHTML = prop;

这是完整的 function:

function onItemClick() {
    for (var prop in itemNames) {
        if (itemNames[prop].includes(value1) && itemNames[prop].includes(value2)) {
            value1 = "";
            value2 = "";
            let itemDiv = document.createElement("div");
            let imageDiv = document.createElement("div");
            let imgEl = document.createElement("img");
            let itHeading = document.createElement("h6");

            let itemslistcontent = document.getElementById("items");

            itemslistcontent.appendChild(itemDiv);
            itemDiv.appendChild(imageDiv);
            imageDiv.appendChild(imgEl);
            itemDiv.appendChild(itHeading);
            itemDiv.classList.add("item");
            itemDiv.setAttribute("value", prop);
            itHeading.innerHTML = prop;


            console.log(itemslistcontent);
        } else {
            value1 = "";
            value2 = "";
        }
    }
}

当您以编程方式向 DOM 添加新元素时,这些元素称为动态元素。

由于在将动态元素添加到 DOM 时您的代码已经运行,因此事件侦听器仅注册到在代码执行时已经存在的元素。

因此,您需要将事件侦听器再次添加到动态组件中。

另外,为什么不使用 JavaScript 中的dblclick事件呢?

尝试以下代码,它在创建动态元素时添加偶数侦听器。

function onItemClick() {
    for (var prop in itemNames) {
        if (itemNames[prop].includes(value1) && itemNames[prop].includes(value2)) {
            value1 = "";
            value2 = "";
            let itemDiv = document.createElement("div");
            let imageDiv = document.createElement("div");
            let imgEl = document.createElement("img");
            let itHeading = document.createElement("h6");

            let itemslistcontent = document.getElementById("items");

            itemslistcontent.appendChild(itemDiv);
            itemDiv.appendChild(imageDiv);
            imageDiv.appendChild(imgEl);
            itemDiv.appendChild(itHeading);
            itemDiv.classList.add("item");
            itemDiv.setAttribute("value", prop);
            itHeading.innerHTML = prop;


            console.log(itemslistcontent);

            // adding the event listener

            itemDiv.addEventListener("dblclick", function() {

                value2 = button.getAttribute("value");
                clickCount = 0;
                onItemClick();
            }); 
        } else {
            value1 = "";
            value2 = "";
        }
    }
}

事件委托

跟踪任何数量的任何元素(无论是否动态添加)上的任何事件(即"click" )的最简单方法是使用事件委托

  • 注册一个元素,该元素将或包含我们想要通过"click"事件监视/控制的所有按钮。

     // Event Property document.querySelector('main').onclick = clickHandler;

    或者

    // EventListener document.querySelector('main').addEventListener('click', clickHandler);
  • 每当单击此父元素时, function clickHandler()都会运行。 此事件处理程序(只是由事件触发的 function 的更具描述性的名称)会将事件委托给用户单击的确切按钮:

    • 使用event.target属性来引用用户单击的元素。

    • 通过使用if/if else/else条件和.matches()方法来缩小范围。

     if (event.target.matches('button')) {...

优点

  • 我们只需要将事件注册到单个父元素 可以使用windowdocument ,但最好使用像<main><form> IMO 这样的元素。 可以使用event.currentTarget属性引用此父元素。

     const listener = event.currentTarget; console.log(listener.tagName); // MAIN
  • 可以选择event.currentTarget的任何后代元素 如果用户单击了一个元素(即<button> ),则可以直接使用event.target属性引用它。 如果所需的元素不是event.target ,而是它的邻近性,我们可以通过多种方式间接引用它。

     <main> <section class='group'> <figure class='item'> <img src='pix.jpg'> <figcaption> <input> <button>X</button> <label>XXXX</label>... const clicked = event.target; if (clicked.matches('button')) { let group = clicked.closest('.group'); let item = clicked.closest('.item'); let tag = clicked.nextElementSibling; let txt = clicked.previousElementSibling; ... /* Reference to the <section>, <figure>, <input>, and <label> and finding the exact element clicked by user */
  • 此委托还包括任何动态添加的元素。 新手常犯的一个错误是期望添加到 DOM 的元素是可点击的,但不是因为它们需要注册到事件中(即.onclick或 .addEventListener .addEventListener('click') )。 使用事件委托,这绝不是一个问题。 event.currentTarget; 仅此而已。

演示

 const main = document.querySelector('main'); main.onclick = clickHandler; function clickHandler(event) { const listener = event.currentTarget; const clicked = event.target; let grpIdx = indexNodes('.group'); let itmIdx = indexNodes('.item'); const itemHTMLString = ` <figure class='item'> <img src="https://placeimg.com/100/100/any"> <figcaption> <b>Item ${itmIdx+1}</b><button>&#128128;</button> <output class='count'>0</output> </figcaption> </figure>`; const groupHTMLString = ` <section class='group'> <fieldset> <legend>Group ${grpIdx+1} Total Clicks</legend> <output class='total'>1</output> </fieldset> <figure class='item'> <img src="https://placeimg.com/100/100/any"> <figcaption> <b>Item ${itmIdx+1}</b><button>&#128128;</button> <output class='count'>1</output> </figcaption> </figure> </section>`; let item, group, count, total; if (clicked.matches('button')) { item = clicked.closest('.item'); group = clicked.closest('.group'); count = clicked.nextElementSibling; total = group.querySelector('.total'); let cnt = parseInt(count.textContent, 10); let ttl = parseInt(total.textContent, 10); if (ttl < 3) { total.textContent = ttl + 1; count.textContent = cnt + 1; group.insertAdjacentHTML('beforeend', itemHTMLString); indexNodes('.group'); indexNodes('.item'); } else if (ttl === 3) { let buttons = group.querySelectorAll('button'); for (let btn of buttons) { btn.disabled = true; } listener.insertAdjacentHTML('beforeend', groupHTMLString); indexNodes('.group'); indexNodes('.item'); } else { return false; } } else { return false; } } function indexNodes(selector) { const nodes = document.querySelectorAll(selector); nodes.forEach((node, index) => node.dataset.idx = index); return nodes.length; }
 * { margin: 0; padding: 0; } main { margin: 10px auto; padding: 8px; }.group { display: flex; flex-flow: row nowrap; justify-content: flex-start; margin: 8px auto; padding: 4px; } fieldset { margin-top: -20px } legend { font-size: large; font-weight: bold; } figcaption { display: flex; flex-flow: row nowrap; justify-content: flex-end; } button, b, output { display: block; font-size: large; } b { text-align: left; padding: 8px 8px 0 8px; font-size: small; }.count { padding: 8px 8px 0 8px; }.total { margin: 0 auto; text-align: center; } button { cursor: pointer; max-height: 28px; }
 <:DOCTYPE html> <html lang='en'> <head> <meta charset='utf-8'> </head> <body> <main> <section class='group' data-idx='0'> <fieldset> <legend>Group 1 Total Clicks</legend> <output class='total'>1</output> </fieldset> <figure class='item' data-idx='0'> <img src="https.//placeimg;com/100/100/any"> <figcaption> <b>Item 1</b><button>&#128128;</button> <output class='count'>1</output> </figcaption> </figure> </section> </main> </body> </html>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM