如何在开始时不存在的动态创建的元素上添加事件处理程序

How to add event handlers on elements created dynamically which are not present at the start

我是 javascript 的新手,目前正在制作类似 this 的待办事项列表。

我正在尝试使用 javascript 使列表项在单击时变为绿色。这是我当前的代码:

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TODO</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400&family=PT+Sans&family=Roboto:wght@300;400;500;700&family=Rubik:wght@700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <script src="https://kit.fontawesome.com/7fa743e7fb.js" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="app.css">
</head>
<body>
    <h1>WORK TO-DOS</h1>
    <p id="desc">Enter text into the input field to add items to your list.</p>
    <p id="compl-desc">Click the item to mark it as complete.</p>
    <p id="rem-desc">Click the "X" to remove the item from your list.</p>
    <section id="input-block">
        <input type="text" name="todo" id="todo" placeholder="New Item">
        <button id="submit"><i class="fa-solid fa-file-pen"></i></button>
    </section>
    <ul class="todo-area"></ul>
    <script src="app.js"></script>
    <!-- tst div -->
    <!-- <div class='test-div'>
        <span>lor</span>
        <button id="delete-li">
            <i class="fa-solid fa-xmark"></i>
        </button>
    </div> -->
</body>
</html>

CSS:

body {
    height: 100vh;
    background-color: #04a1bf;
    display:flex;
    flex-direction: column;
    align-items: center;
    /* justify-content: center; */
}

h1 {
    font-size: 3.0rem;
    color: white;
    font-family: 'Rubik', sans-serif;
}

p {
    font-family: 'Roboto', sans-serif;
    font-weight: 500;
}

/* changing colors */
#desc {
    color: yellow;
}

#compl-desc {
    color:greenyellow
}

#rem-desc {
    color: #025f70;
}

section {
    width: 70%;
    height: 60px;
}

#todo {
    height: 55%;
    width: 90%;
    border-radius: 5px;
    border: none;
    /* margin-right: 10px; */
}

#submit {
    border: none;
    height: 55%;
    width: 7%;
    font-size: 0.8rem;
    border-radius: 0.5em;
    background-color: #025f70;
    color:aliceblue;
    transition-property: all;
    transition-duration: 0.5s;
    /* transition-timing-function: cubic-bezier(0.075, 0.82, 0.165, 1); */
}

#submit:hover {
    background-color: #02798f;
    color: bisque;
    cursor: pointer;
    height: 55%;
    /* border: 1px solid black; */
}

.todo-area {
    list-style-type: none;
    padding:0%;
    width: 60%;
}

.todo-item {
    /* width: 60%; */
    background-color: #4eb9cd;
    padding: 8px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-radius: 10px;
    border-color: #025f70;
    border-width: 3px;
    border-style: solid;
    transition: background-color 0.5s;
    margin: 10px 0px;
}

.todo-item:hover {
    background-color: #76cfe0;
}

.todo-item-complete {
    background-color: #51df70;
    color: #0f8d2a;
}

#delete-li {
    border: none;
    background-color: #4eb9cd;
    margin-right:2%;
    transition: background-color 0.5s;
}

.todo-item:hover #delete-li {
    background-color: #76cfe0;
}

Javascript:

const todoUl = document.querySelector('.todo-area');
const input = document.querySelector('#todo');
const addBtn = document.querySelector('#submit');
console.log('input', input['value'])

function createLi(inputText) {
    // this function creates the li with the delete button
    // creating the Li first
    const li = document.createElement('li');
    // add class to li
    li.classList.add('todo-item');
    //  making the button
    const delBtn = document.createElement('button');
    delBtn.setAttribute('id', 'delete-li');
    // icon
    const btnIcon = document.createElement('i');
    btnIcon.classList.add('fa-solid');
    btnIcon.classList.add('fa-xmark');
    // adding that to the delete button
    delBtn.appendChild(btnIcon)
    
    // adding text to the element from the input
    // creating a span
    const liSpan = document.createElement('span');
    liSpan.innerText = inputText;
    li.appendChild(liSpan);
    li.appendChild(delBtn);
    
    return li
}

addBtn.addEventListener('click', () => {
    // getting value in text box
    let todoText = input.value;
    console.log('button clicked');
    console.log(todoText);
    // adding to the ul element
    if(todoText !== "") { 
        let newLi = createLi(todoText);
        // adding class to the li
        // newLi.classList.add('todo-item');
        todoUl.appendChild(newLi);
    }
    // resetting the text box blank again
    input.value = '';
})

// getting all the list items
const listItems = document.querySelectorAll('.todo-item');

// turning them green once they are clicked
for(let li of listItems) {
    // adding an onclick event on them
    li.addEventListener('click', () => {
        // adding the active class
        console.log('LI CMD');
        li.classList.toggle('todo-item-complete');
    })
}

这显然不起作用。虽然我想我知道为什么它不起作用。我需要知道如何为因页面中的某些操作而动态生成的元素设置事件处理程序。

您应该在创建 li 时添加 eventListener 喜欢

function createLi(inputText) {
    // this function creates the li with the delete button
    // creating the Li first
    const li = document.createElement('li');
    // add class to li
    li.classList.add('todo-item');
    //  making the button
    const delBtn = document.createElement('button');
    delBtn.setAttribute('id', 'delete-li');
    // icon
    const btnIcon = document.createElement('i');
    btnIcon.classList.add('fa-solid');
    btnIcon.classList.add('fa-xmark');
    // adding that to the delete button
    delBtn.appendChild(btnIcon)
    
    // adding text to the element from the input
    // creating a span
    const liSpan = document.createElement('span');
    liSpan.innerText = inputText;
    li.appendChild(liSpan);
    li.appendChild(delBtn);
        li.addEventListener('click', () => {
        // adding the active class
        console.log('LI CMD');
        li.classList.toggle('todo-item-complete');
    })
    
    return li
}