如何删除包含动态生成的唯一ID的div



我对JS还很陌生,如果我不够清楚的话,很抱歉。

我正在创建一个待办事项列表。我为添加的每个新任务生成了一个div。每个div包含两个类。

  1. 一个通用的
  2. 使用new Date((.getTime((的唯一ID

现在我需要允许删除特定的任务。但我似乎无法使用唯一ID删除div。这可能是因为我没有取回数据?如何解决?

const myArray = [];
function myPushFunction(x){ // 3rd
let itemToPush = myArray.push(x);
return itemToPush;
}
function getMyInputValue(){
let myInputValue = document.querySelector("#myInput").value;
document.querySelector("#TasksList").innerHTML + myInputValue; 
myPushFunction(myInputValue); 
let taskScope = document.querySelector("#TasksList");
let div1 = document.createElement("div");
taskScope.appendChild(div1);

let addItem = document.createTextNode(myInputValue);
div1.appendChild(addItem);
let idClass = "p" + new Date().getTime();
div1.classList.add("taskdesign", idClass);
let buttonDelete = document.createElement("BUTTON");
div1.appendChild(buttonDelete);
buttonDelete.classList.add("buttondeletedesign");
let span = document.createElement("SPAN");
span.innerHTML = "delete";
buttonDelete.appendChild(span);
span.classList.add("material-icons-outlined");
buttonDelete.onclick = function(event) {
const deleteElement = document.querySelector(`.${idClass}`);
deleteElement.remove();
}

}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="todo-design.css">

<link href="https://fonts.googleapis.com/css2?family=Jost:wght@500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;400;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined" rel="stylesheet">
<title>Toudou</title>
</head>
<body>
<div id="myfullpage">
<h1>Toudou</h1>
<div id="NewTask">
<input type="text" id="myInput" placeholder="Task to add">
<button id="button" onclick="getMyInputValue()">Add</button>
</div>
<div id="TasksList"></div>

<script type="text/javascript" src="testjs-1.js"></script>
</div>
</body>
</html>

感谢

唯一ID

您首先需要的是待办事项列表中任务的唯一ID。时间不是一个很好的候选者,因为如果你以编程方式创建任务,两个时间戳可能会得到相同的ID。请参阅下面的示例脚本,它显示指令执行得如此之快,以至于它们具有相同的时间戳。

const timestamp = new Date()
const timestamp2 = new Date()
console.log(timestamp.getTime())
console.log(timestamp2.getTime())

由于JavaScript是单线程的,我们可以使用一个简单的计数器。另一种可能是UUID。

在下面提供的实现中,我使用了一个简单的计数器。请参见类ToDoList的私有类属性#curId

任务

您应该将任务保存在一个数据结构中,例如一个简单的数组,以便以结构化的形式准备好所有任务信息,供您的程序使用。这是你的状态。使用它,管理您的应用程序比将这些信息放在HTML中的类、ID等中要容易得多

在下面提供的实现中,我使用了一个简单的数组来保存任务。参见ToDoList中的私有类属性#tasks。我的实现中的一个任务只是我的Task类的一个实例,所以#tasks是由ToDoList类的实例管理的Task实例的数组。

如何删除

当您将删除按钮附加到每个任务,并将事件处理程序附加到该删除按钮时,可以执行删除。每当点击该按钮时,事件处理程序就会被触发,并应执行以下步骤:

  • 从任务数组中删除任务(=state(
  • 从视图中删除任务(=HMTL页面(

为了识别任务,我们使用其唯一ID,并将该ID作为参数提供给删除按钮的onclick处理程序。我在创建删除按钮时会这样做,因为此时我们知道该按钮将删除哪个任务。

请参阅下面提供的实现中ToDoList类的方法#addTaskToView()#createDeleteButton()按钮方法,以了解我是如何做到这一点的。

实施:待办事项列表

我实现了一个非常简单的待办事项列表,它只能从预定义的任务列表中删除任务(使用UI(,但可以很容易地将其扩展为能够添加任务等等。

我的实现是面向对象的,因为它对给定的任务非常有效,甚至允许将ToDo列表视为应用程序中的一个独立组件,类似于React等前端框架的做法。我的代码片段展示了如何使用两个简单的命令new ToDoList()轻松创建两个ToDoList。

你可能想阅读我在MDN文档中使用的一些功能,其中最重要的是:

  • 私人课堂特色
  • JSDoc

/**
* For demo purposes assume a user already had created these tasks
*/
const tasks = [
{
title: "My task 1",
desc: "Desc for my task",
},
{
title: "My task 2",
desc: "Desc for my task 2",
},
{
title: "My task dfssdf",
desc: "Desc for my task fsddsfsd",
},
{
title: "My task 1",
desc: "Desc for my task",
},
{
title: "My task 2",
desc: "Desc for my task 2",
},
{
title: "My task dfssdf",
desc: "Desc for my task fsddsfsd",
},
];
class Task {
/**
* @private
* @type {number}
*/
#id;
/**
* @private
* @type {string}
*/
#title;
/**
* @private
* @type {string}
*/
#description;
constructor(id, title, description) {
this.#id = id;
this.#title = title;
this.#description = description;
}
/**
* Create a copy of an existing task.
* @param {Task} task task to create a copy from
* @returns deep copy of given task
*/
static #from(task) {
return new Task(task);
}
/**
* Copy the task.
* @returns 1:1 deep-copy of the task
*/
clone() {
return Task.#from(this);
}
get id() {
return this.#id;
}
get title() {
return this.#title;
}
get description() {
return this.#description;
}
}
class ToDoList {
/**
* List of tasks in this ToDo list.
* @private
* @type {Array<Task>}
*/
#tasks;
/**
* Current ID. Counter used to assign a unique ID to a task within the list
* @private
* @type {number}
*/
#curId;
/**
* <ul> tag that contains all list items
* @private
* @type {HTMLUListElement}
*/
#list;
/**
* Root HTML element this list is attached to.
* @private
* @type {HTMLElement}
*/
#root;
/**
* Create a new ToDo list.
* @param {HTMLElement} attachTo root element this ToDo list is attached to
* @param {string} title title for the ToDo list
*/
constructor(attachTo, title) {
this.#tasks = [];
this.#curId = 1;
if (!attachTo instanceof HTMLElement) throw "No valid wrapper element given!";
this.#root = attachTo;
this.#list = this.#createList()
this.#addToDoListToView(title)
}
/**
* Initialize the ToDo list 
* @param {string} title title for todo list
*/
#addToDoListToView(title){
const header = this.#createToDoListHeader(title);
this.#root.append(header, this.#list);
}
#createList(){
return document.createElement("ul");
}
#createToDoListHeader(title){
const heading = document.createElement("h1");
heading.textContent = title;
return heading;
}
get tasks() {
// SoC: return copy; don't let callers manipulate the state of the actual task array
return this.#tasks.slice();
}
get curId() {
return this.#curId;
}
get wrapper() {
return this.#list;
}
/**
* Add a newly created task to the view.
* @param {Task} newTask new task
*/
#addTaskToView(newTask) {
// new list item as a parent
const listItem = document.createElement("li");
listItem.classList.add("task");
// a heading for the title
const heading = document.createElement("h3");
// create blockquote to show ID of a task
const taskId = document.createElement("span");
taskId.classList.add("id");
// a paragraph for the description
const desc = document.createElement("p");
// create the delete button
const deleteBtn = this.#createDeleteButton(newTask, listItem);
// set text values for created elements
heading.textContent = newTask.title;
desc.textContent = newTask.description;
taskId.textContent = `Task-ID: ${newTask.id}`;
// build structure
listItem.append(taskId, heading, desc, deleteBtn);
// append to actual TODO list
this.#list.appendChild(listItem);
}
/**
* Create the delete button for a task.
* @param {Task} newTask new task
*/
#createDeleteButton(newTask, listItem) {
// create a Button to delete the task
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
// here is the important part! Pass the task ID to the delete function that will be called whenever the button is clicked
deleteBtn.onclick = () => {
const success = this.deleteTaskById(newTask.id);
if (!success) {
alert(
`Task "ID: ${newTask.id} | ${newTask.title} does not exits and therefore could not be deleted!`
);
return;
}
this.#deleteTaskFromView(listItem);
};
return deleteBtn;
}
/**
*
* @param {string} title title for the task
* @param {string} description description for the task
* @returns newly created task
*/
addTask(title, description) {
// better to use an ID that is unique (one could also use UUIDs but for simplicity just count the IDs up)
const newTask = new Task(this.#curId++, title, description);
this.#tasks.push(newTask);
// now add the task to the HTML document
this.#addTaskToView(newTask);
// return a copy of the newly created task, SoC: don't allow callers to manipulate internal objects
return newTask.clone();
}
/**
* Delete a task given its ID.
* @param {number} id unique ID for a task
* @returns true if task with given ID was found and deleted, false otherwise
*/
deleteTaskById(id) {
const foundIdx = this.#tasks.findIndex((task) => task.id === id);
if (foundIdx !== -1) {
this.#tasks.splice(foundIdx, 1)[0];
return true;
}
return false;
}
/**
* Delete a task from the HTML document using it's ID
* @param {HTMLUListElement} listItem list element containing this task
*/
#deleteTaskFromView(listItem) {
listItem.parentNode.removeChild(listItem);
}
}
window.addEventListener("DOMContentLoaded", (event) => {
// container which holds the TODO list
const container = document.getElementById("container1");
const container2 = document.getElementById("container2");
// create the todo list and specify the HTML element it should be attached to
const todoList = new ToDoList(container, "My ToDo List");
const todoList2 = new ToDoList(container, "2nd ToDo List");
// add task list with some predefined tasks
tasks.forEach((task) => {
todoList.addTask(task.title, task.desc)
todoList2.addTask(task.title, task.desc)
});
});
.task{
border-radius: 0.5rem;
border: 1px solid black;
list-style: none;
padding: 1rem;
margin: 0.5rem;
}
.id {
font-size: small;
color: gray;
}
<div id="container1"></div>
<div id="container2"></div>

不使用ID的示例以及如何在单击处理程序中定位正确的元素。

const deleteButtons = document.querySelectorAll("button.deleteBtn");
for (let d of deleteButtons) {
d.addEventListener("click", (e) => {
// e.target is the button that was clicked!
let theButton = e.target;
// theButton.parentNode is the div that the button is in!
let theDiv = theButton.parentNode;
theDiv.remove();
});
}
<div id="myfullpage">
<h1>Toudou</h1>
<div id="TasksList">
<div class="task">
<span>task1</span>
<button class='deleteBtn'>Delete</button>
</div>
<div class="task">
<span>task2</span>
<button class='deleteBtn'>Delete</button>
</div>
<div class="task">
<span>task3</span>
<button class='deleteBtn'>Delete</button>
</div>
</div>
</div>

最新更新