Javascript 如何使用JS created按钮删除JS created LI?

Javascript 如何使用JS created按钮删除JS created LI?,javascript,html,dom,Javascript,Html,Dom,我正在用JavaScript创建一个TODO应用程序。我如何理解如何链接两个创建的JavaScript项并将它们从DOM中删除 TL;DR:我经常遇到的问题是在创建列表项后在DOM中导航。我曾尝试对创建的元素使用一个带有“id”标记的setAttribute,但我仍然能够找到如何迭代LI来查找按下了哪个按钮 代码: <div class="entry-field"> <label class="task-input" for="task-in

我正在用JavaScript创建一个TODO应用程序。我如何理解如何链接两个创建的JavaScript项并将它们从DOM中删除

TL;DR:我经常遇到的问题是在创建列表项后在DOM中导航。我曾尝试对创建的元素使用一个带有“id”标记的setAttribute,但我仍然能够找到如何迭代LI来查找按下了哪个按钮

代码:

        <div class="entry-field">
          <label class="task-input" for="task-input">Task:</label>
          <input type="text" class="task-field" placeholder="Enter Item"/>
          <button class="add-btn">ADD</button>
        </div>
        <section class="task-list">
          <h2>Task List</h2>
          <div class="list-wrap"></div>
            <ul class="item-log">
              <li class="list-item">
                <span class="item-text">this is the item</span>
                <button class="delete-btn">delete</button>
              </li>
            </ul>
          </div>
        </section>
      </main>

JavaScript:
let index = 0;

//Obtaining user text, creating a Span element, append span with user text:
function addItem() {
  let itemLog = document.querySelector(".item-log");
  let listItem = document.createElement("LI");
  let deleteBtn = document.createElement("BUTTON");
  let userEntry = document.querySelector(".task-field").value;
  let spanItem = document.createElement("SPAN");
  index++;
  //Creating LI "list-item" and append UL "itemLog"
  itemLog.appendChild(listItem);
  listItem.classList.add("list-item");

  listItem.setAttribute("id", index);
  //Create Span element, assign text from user input, append LI
  spanItem.innerHTML = userEntry;
  listItem.appendChild(spanItem);
  //Create deleteBtn and append to LI
  deleteBtn.innerHTML = "Delete";
  deleteBtn.classList.add("delete-btn");
  deleteBtn.setAttribute("onclick", "deleteItem()");
  deleteBtn.setAttribute("id", index);
  listItem.appendChild(deleteBtn);

  userEntry.value = "";
}

/*
2) Deleting item from list:
  -use event listener to trigger parent node
  -delete child
  */

function deleteItem() {
  let listItem = this.parentElement;
  listItem.parentElement.removeChild(listItem);
}

// Page event listeners
let addBtn = document.querySelector(".add-btn");

addBtn.addEventListener("click", addItem);


任务:
添加
任务列表
  • 这是项目 删除
JavaScript: 设指数=0; //获取用户文本、创建Span元素、使用用户文本附加Span: 函数addItem(){ 让itemLog=document.querySelector(“.itemLog”); 让listItem=document.createElement(“LI”); 让deleteBtn=document.createElement(“按钮”); 让userEntry=document.querySelector(“.task field”).value; 设spanItem=document.createElement(“SPAN”); 索引++; //创建LI“列表项”并附加UL“项目日志” appendChild(listItem); listItem.classList.add(“列表项”); setAttribute(“id”,索引); //创建Span元素,根据用户输入指定文本,追加LI spanItem.innerHTML=userEntry; listItem.appendChild(spanItem); //创建deleteBtn并附加到LI deleteBtn.innerHTML=“删除”; deleteBtn.classList.add(“deleteBtn”); setAttribute(“onclick”,“deleteItem()”); deleteBtn.setAttribute(“id”,索引); listItem.appendChild(deleteBtn); userEntry.value=“”; } /* 2) 正在从列表中删除项目: -使用事件侦听器触发父节点 -删除子项 */ 函数deleteItem(){ 让listItem=this.parentElement; listItem.parentElement.removeChild(listItem); } //页面事件侦听器 让addBtn=document.querySelector(“.addBtn”); addBtn.addEventListener(“单击”,添加项);
您的示例中的问题是
这个
在您的
删除项
函数中所指的内容。如果您在
deleteItem
功能中记录console.log,您将看到
指的是窗口,而不是按下的按钮

如果不使用
setAttribute
设置
onClick
,您可以添加一个事件侦听器:
deleteBtn.addEventListener(“单击”,删除项)

deleteItem
函数中,您可以访问事件对象以及该事件的目标,并且代码将按预期工作

function deleteItem(event) {
  let listItem = event.target.parentElement;
  listItem.parentElement.removeChild(listItem);
}

在任何鼠标事件侦听器上,始终会有一个
MouseEvent
参数传递给事件处理程序。该
MouseEvent
对象具有属性
target
,该属性是作为事件目标的
HTMLElement
。例如:

let div=document.querySelector('div.button');
设toggleState=0;
让消息=[“单击!”,“单击我!”;
let handler=函数(事件){
event.target.innerText=消息[toggleState];
切换状态^=1;
}
div.addEventListener(“单击”,处理程序,false)
点击我
  • 在创建删除元素时指定一个单击处理程序
  • 创建要预填充的任务数组
const myTasks=[
“这是物品”,
“嗯,这是另一项”
];
const EL_text=document.querySelector(“#text”);
const EL#u add=document.querySelector(“#add”);
const EL_tasks=document.querySelector(“#tasks”);
函数addTask(文本){
//确定是否有文本字符串参数(预填充)
//否则,获取输入值:
text=typeof text===“string”?text:EL_text.value.trim();//修剪您的值!
if(!text)return;//如果没有值,则不执行任何操作!
const EL_task=document.createElement('li');
const EL_delete=document.createElement('button');
EL_delete.textContent=“删除”;
EL_delete.addEventListener('click',()=>EL_task.remove());
EL_task.insertAdjacentHTML('afterbegin','${text}');
EL_task.appendChild(EL_delete);
EL_tasks.appendChild(EL_task);
EL_text.value='';//清除当前输入文本值
}
EL_add.addEventListener(“单击”,添加任务);
//预填充
myTasks.forEach(addTask)
#任务{
填充:0;
列表样式:无;
}
#任务李{
显示器:flex;
背景:#eee;
填充:0.6em;
边缘底部:0.5em;
边界半径:0.4em;
}
#李分区{
弹性:1;
}
任务:
添加

    在创建必须动态插入类似元素并通过ID系统跟踪它们的应用程序时,我建议使用一种更有条理的方法来消除代码中的任何混乱

    对于基本应用程序,您可以创建自定义类,每个类都有
    元素
    模板
    ui
    uiEventCallbacks
    切换uievents
    呈现
    方法。在每个类中,
    元素
    将是一个包含
    模板
    标记的主HTML元素。
    render
    方法解析
    模板
    文本并将其分配给
    元素.innerHTML
    。要实例化应用程序,只需创建基类的新实例,呈现它,然后将元素附加到主体

    我用您的标记创建了一个Todo应用程序。有
    TodoApp
    Todo
    Todo
    类。
    TodoApp
    包含
    Todo
    ,而
    Todo
    包含
    Todo
    的实例

    待办事项

    const Todo = class {
      constructor(settings) {
        this.settings = settings
      }
      get settings() { return this._settings }
      set settings(settings) { this._settings = settings }
      get element() {
        if(!this._element) {
          this._element = document.createElement('li')
          this._element.setAttribute('class', 'list-item')
          this._element.setAttribute('id', this.settings.id )
        }
        return this._element
      }
      get ui() { return {
        deleteButton: this.element.querySelectorAll(':scope > .delete-btn'),
      } }
      get uiEventCallbacks() { return {
        deleteButtonClick: (event) => {
          let customEvent = new CustomEvent('removeTodo', {
            bubbles: true,
            details: {
              id: this.settings.id
            }
          })
          this.element.dispatchEvent(
            customEvent
          )
        },
      } }
      remove() { 
        this.element.parentElement.removeChild(this.element)
        }
      template() { return `
        <span>${this.settings.value}</span>
        <button class="delete-btn">Delete</button>
      ` }
      toggleUIEvents() {
        [
          'removeEventListener',
          'addEventListener'
    
        ].forEach((eventMethod) => {
          this.ui.deleteButton.item(0)[eventMethod]('click', this.uiEventCallbacks.deleteButtonClick)
        })
      }
      render() {
        const template = this.template()
        this.element.innerHTML = template
        this.toggleUIEvents()
        return this
      }
    }
    
    const Todos = class {
        constructor() {}
      get element() {
        if(!this._element) {
          this._element = document.createElement('section')
          this._element.setAttribute('class', 'task-list')
        }
        return this._element
      }
      get ui() { return {
        itemLog: this.element.querySelectorAll('.item-log')
      } }
      get uiEventCallbacks() { return {
        removeTodo: (event) => {
          console.log(event)
          this.removeTodo()
        },
      } }
      get todos() {
        this._todos = this._todos || []
        return this._todos
      }
      template() { return `
        <h2>Task List</h2>
        <div class="list-wrap">
          <ul class="item-log"></ul>
        </div>
      ` }
      toggleUIEvents() {
        [
          'removeEventListener',
          'addEventListener'
        ].forEach((eventMethod) => {
          this.ui.itemLog.item(0)[eventMethod]('removeTodo', this.uiEventCallbacks.removeTodo)
        })
      }
      addTodo(data) {
        const todo = new Todo(data)
        this.todos.push(todo)
        this.ui.itemLog.item(0).appendChild(
          todo.render().element
        )
        return this
      }
      removeTodo(id) {
        let todoIndex = this.todos.reduce((_todoIndex, todo, todoIndex) => {
          if(todo.id === id) _todoIndex = todoIndex
          return _todoIndex
        }, -1)
        let todo = this.todos.splice(todoIndex, 1)[0]
        todo.remove()
        return this
      }
      render(data) {
        const template = this.template(data)
        this.element.innerHTML = template
        this.toggleUIEvents()
        return this
      }
    }
    
    const TodoApp = class {
      constructor() {}
      get element() {
        if(!this._element) {
          this._element = document.createElement('main')
        }
        return this._element
      }
      get ui() { return {
        addButton: this.element.querySelectorAll('.add-btn'),
        input: this.element.querySelectorAll('.task-field'),
      } }
      get uiEventCallbacks() { return {
        addTodo: (event) => {
          let taskFieldData = this.ui.input.item(0).value
          this.todos.addTodo({
            id: this.uuid(),
            value: taskFieldData,
          })
        },
      } }
      get todos() {
        this._todos = this._todos || new Todos()
        return this._todos
      }
      uuid() {
        var uuid = '', i, random
        for (i = 0; i < 32; i++) {
          random = Math.random() * 16 | 0
          if (i === 8 || i === 12 || i === 16 || i === 20) {
            uuid += "-"
          }
          uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16)
        }
        return uuid
      }
      template() { return `
        <div class="entry-field">
          <label class="task-input" for="task-input">Task:</label>
          <input type="text" class="task-field" placeholder="Enter Item"/>
          <button class="add-btn">ADD</button>
        </div>
      ` }
      toggleUIEvents() {
        [
          'removeEventListener',
          'addEventListener'
        ].forEach((eventMethod) => {
          this.ui.addButton.item(0)[eventMethod]('click', this.uiEventCallbacks.addTodo)
        })
      }
      render(data) {
        const template = this.template(data)
        this.element.innerHTML = template
        this.element.appendChild(this.todos.render().element)
        this.toggleUIEvents()
        return this
      }
    }
    

    谢谢你的帮助。这是一个简单的解决方案。理解这个解决方案时,我的问题是:为什么delete函数必须放在addItem()函数中?我假设它与范围有关,但我不明白为什么它不能在功能之外为或生存
    const todoApp = new TodoApp()
    const body = document.querySelector('body')
    body.insertAdjacentElement('afterbegin', todoApp.render().element)