如何在点击处理程序中获取正确的项目

How do I get the correct item in a clickhandler

我有以下代码: HTML:

<div id="root">
  <form class="todoForm">
    <input class="input" placeholder="What's gotta be done'?" />
  </form>
  <div class="todos"></div>
  <div class="footer">
    <button class="All">All</button>
    <button class="Active">Active</button>
    <button class="Completed">Completed</button>
    <button class="Clear">Clear</button>
  </div>
</div>

CSS:

.todoForm {
  margin-bottom: 20px;
}

.todos {
  margin-bottom: 20px;
}

.todo {
  margin-bottom: 10px;
}

.todoAndCheckBox {
  display: flex;
  font-weight: bold;
}

.checkBox {
  border-radius: 50%;
  outline: green;
}

.crossOut {
  font-weight: normal;
  text-decoration: line-through
}

JS:

const COMPLETED = 'completed';
const ACTIVE = 'active';
const ALL = 'all';

class displayTodos {
  constructor(root) {
    this.root = root;
    this.input = this.root.querySelector('.input');
    this.form = this.root.querySelector('.todoForm');
    this.form.addEventListener('keydown', this.submitForm);
    this.todos = this.root.querySelector('.todos');
    this.store = {
      todos: [
        {
          id: Math.random() * 10000,
          text: 'Banana',
          state: COMPLETED,
        },
        {
          id: Math.random() * 10000,
          text: 'Ice cream',
          state: ACTIVE
        }
      ],
    }
    
    this.AllButton = this.root.querySelector('.All');
    this.ActiveButton = this.root.querySelector('.Active');
    this.CompletedButton = this.root.querySelector('.Completed');
    
    this.display();
  }
  
  submitForm = (e) => {
    if(e.key === 'Enter') {
      e.preventDefault();
      const typed = this.input.value;
      const newTodo = {
        id: Math.random * 10000,
        text: typed,
        state: ACTIVE
      }
      
      const newTodos = [...this.store.todos, newTodo];
      
      this.store.todos = newTodos;
      this.display();
      this.input.value = ''
    }
  }
  
  display = () => {
    while(this.todos.firstChild) {
      this.todos.removeChild(this.todos.firstChild)
    }
    this.store.todos.forEach(todo => {
      const { id, text, state } = todo;
      const todoAndCheckBox = document.createElement('div');
      
      const todoDiv = document.createElement('div');
      todoAndCheckBox.classList.add('todoAndCheckBox');
      todoDiv.innerText = todo.text;
      
      const checkBox = document.createElement('input');
      checkBox.setAttribute('type', 'checkbox');
      checkBox.classList.add('checkBox');
      
      this.todos.appendChild(todoAndCheckBox);
      
      todoAndCheckBox.appendChild(checkBox);
      todoAndCheckBox.appendChild(todoDiv);
      todoAndCheckBox.classList.add('todo');
      todoAndCheckBox.addEventListener('click', (e, todo) => this.clickHandler(e, todo));
      this.displayCount(this.AllButton, ALL);
      this.displayCount(this.ActiveButton, ACTIVE);
      this.displayCount(this.CompletedButton, COMPLETED);
    })
  }
  
  clickHandler = (e, todo) => {
    e.currentTarget.classList.toggle('crossOut');
    console.log(todo, 'todo')
    todo.state = todo.state === COMPLETED ? ACTIVE : COMPLETED
  }
  
  displayCount = (button, type) => {
    let count = 0;
    if(type === ALL) {
      count = this.store.todos.length;
      button.innerText = `All: ${count}`;
    }
    
    if(type === ACTIVE) {
      const filtered = this.store.todos.filter(todo => todo.state === ACTIVE);
      count = filtered.length;
      button.innerText = `Active: ${count}`;
    }
    
    if(type === COMPLETED) {
      const filtered = this.store.todos.filter(todo => todo.state === ACTIVE);
      count = filtered.length;
      button.innerText = `Completed: ${count}`;
    }
    
  }
}

const root = document.querySelector('#root');
const instance = new displayTodos(root);

期望的结果是当我单击以划掉待办事项时,ActiveCompleted 按钮将显示适当的计数。但是,在这个函数中:

clickHandler = (e, todo) => {
    e.currentTarget.classList.toggle('crossOut');
    console.log(todo, 'todo')
    todo.state = todo.state === COMPLETED ? ACTIVE : COMPLETED
  }

我无法取出 todo 项。当我 console.log 它出来时,它说它是未定义的。我很困惑,因为我确实在这里使用了它:

todoAndCheckBox.addEventListener('click', (e, todo) => this.clickHandler(e, todo));
  1. 为什么我没有收到 todo,我该怎么做才能解决这个问题?
  2. 我注意到如果我将该行重写为
todoAndCheckBox.addEventListener('click', this.clickHandler.bind(this, e, todo));

JS 抱怨 e 没有定义。我如何到达那里 e

您可以在侦听器中使用匿名函数。从那里您可以调用另一个函数或直接处理您的逻辑。

const otherFunction = (e) => {
  console.log(todo); // global
  console.log(e);
}

let todo = {
  thing: 'stuff'
};

let todoAndCheckBox = document.getElementById('todoAndCheckBox');
todoAndCheckBox.addEventListener('click', (e) =>  otherFunction(e));
<button id='todoAndCheckBox'> click </button>

您只需要在侦听器中从匿名函数的参数中删除 todo

通过将 todo 作为参数传递,您将覆盖已经在范围内的 todo,并且该函数正在指定一个未传递给它的参数。

试试这个:

todoAndCheckBox.addEventListener('click', (e) => this.clickHandler(e, todo));