简体   繁体   中英

How can I can make this JavaScript code cleaner?

I'm new to JS and I did this exercise for the course I'm taking. It's basically done, but I had to repeat the code that creates the "delete" button and I'm not sure how I can make this cleaner.

 var button = document.getElementById("add") var input = document.getElementById("userinput") var ul = document.querySelector("ul") var li = document.querySelectorAll("li") function inputLength() { return input.value.length; } function createListElement() { let li = document.createElement("li") li.appendChild(document.createTextNode(input.value)) ul.appendChild(li) input.value = "" // Create a delete button and configure it: var btnDelete = document.createElement("button"); btnDelete.classList.add("delete"); btnDelete.textContent = "Delete"; // Append the button to the list item li.appendChild(btnDelete); } // Create a delete button for each <li> already in the HTML file li.forEach(function(item){ var btnDelete = document.createElement("button"); btnDelete.classList.add("delete"); btnDelete.textContent = "Delete"; item.appendChild(btnDelete); }); function addListAfterClick() { if(inputLength() > 0) { createListElement() } } function addListAfterKeypress(event) { if(inputLength() > 0 && event.keyCode === 13) { createListElement() } } button.addEventListener("click", addListAfterClick) input.addEventListener("keypress", addListAfterKeypress) function toggleClassDoneOnAndOff(event) { if (event.target.tagName === "LI") { event.target.classList.toggle("done"); } } ul.addEventListener("click", toggleClassDoneOnAndOff); function deleteAfterClick(event) { // Determine if it was a delete button that was clicked if(event.target.classList.contains("delete")){ // Remove the closest li ancestor to the clicked element event.target.closest("li").remove(); } } // Handle all the clicks that originate from within the <ul> at // the <ul> level when they bubble up to it instead of setting each // button within the <ul> up with its own click event handler. ul.addEventListener("click", deleteAfterClick);
 .done { text-decoration: line-through; }
 <body> <h1>Shopping List</h1> <p id="first">Get it done today</p> <input id="userinput" type="text" placeholder="Add items"> <button id="add">Add</button> <ul id="ul"> <li>Notebook</li> <li>Jello</li> <li>Spinach</li> <li>Rice</li> <li>Birthday Cake</li> <li>Candles</li> </ul> <script type="text/javascript" src="script.js"></script> </body>

My question is that simple, but since Stack Overflow is telling me to "add some more details"...

Basically, I tried to turn this part into a function:

var btnDelete = document.createElement("button");
btnDelete.classList.add("delete");
btnDelete.textContent = "Delete";

But I couldn't figure out how to make it work inside the other ones.

You'll just extract those 3 lines into their own function and have that function return the newly created element. Where the lines are now will get replaced by the function call.

 var button = document.getElementById("add") var input = document.getElementById("userinput") var ul = document.querySelector("ul") var li = document.querySelectorAll("li") function inputLength() { return input.value.length; } function createDelete(){ // Create a delete button and configure it: var btnDelete = document.createElement("button"); btnDelete.classList.add("delete"); btnDelete.textContent = "Delete"; return btnDelete; // <-- send the new element back to the function caller } function createListElement() { let li = document.createElement("li") li.appendChild(document.createTextNode(input.value)) ul.appendChild(li) input.value = "" // Append the button to the list item // The createDelete() function will be called first // and its return value (the new button) is what will // be appended. li.appendChild(createDelete()); } // Create a delete button for each <li> already in the HTML file li.forEach(function(item){ // The createDelete() function will be called first // and its return value (the new button) is what will // be appended. item.appendChild(createDelete()); }); function addListAfterClick() { if(inputLength() > 0) { createListElement() } } function addListAfterKeypress(event) { if(inputLength() > 0 && event.keyCode === 13) { createListElement() } } button.addEventListener("click", addListAfterClick) input.addEventListener("keypress", addListAfterKeypress) function toggleClassDoneOnAndOff(event) { if (event.target.tagName === "LI") { event.target.classList.toggle("done"); } } ul.addEventListener("click", toggleClassDoneOnAndOff); function deleteAfterClick(event) { // Determine if it was a delete button that was clicked if(event.target.classList.contains("delete")){ // Remove the closest li ancestor to the clicked element event.target.closest("li").remove(); } } // Handle all the clicks that originate from within the <ul> at // the <ul> level when they bubble up to it instead of setting each // button within the <ul> up with its own click event handler. ul.addEventListener("click", deleteAfterClick);
 .done { text-decoration: line-through; }
 <body> <h1>Shopping List</h1> <p id="first">Get it done today</p> <input id="userinput" type="text" placeholder="Add items"> <button id="add">Add</button> <ul id="ul"> <li>Notebook</li> <li>Jello</li> <li>Spinach</li> <li>Rice</li> <li>Birthday Cake</li> <li>Candles</li> </ul> <script type="text/javascript" src="script.js"></script> </body>

you can create this function,

 function createBtnDelete(btn) {
        const btnDelete = document.createElement("button");
        btnDelete.classList.add("delete");
        btnDelete.textContent = "Delete";
        btn.appendChild(btnDelete);
    }

and use li.forEach((btn) => createBtnDelete(btn)); sending each li item as arg then, when you create a new button you can call the same function sending the li you created as a arg like this

function createListElement() {

        let li = document.createElement("li")
        li.appendChild(document.createTextNode(input.value))
        ul.appendChild(li)
        input.value = ""

      
        // Create a delete button and configure it:
        createBtnDelete(li);
       
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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