Javascript 什么会导致单击事件触发多次?

Javascript 什么会导致单击事件触发多次?,javascript,jquery,css,Javascript,Jquery,Css,我有一个小的待办事项清单,是我为练习做的。这是一个 ,我似乎无法理解为什么在todo中切换添加和删除行的类的click事件对某些项目有效,而对其他项目无效。我在控制台中进行了检查,由于某种原因,那些不起作用的按钮在单击时会多次触发。如果有人能告诉我为什么会发生这种情况,我将不胜感激 // Toggle line-through todo $('.todo-container').on('click', function(){ $(this).toggleClass('line-through

我有一个小的待办事项清单,是我为练习做的。这是一个 ,我似乎无法理解为什么在todo中切换添加和删除行的类的click事件对某些项目有效,而对其他项目无效。我在控制台中进行了检查,由于某种原因,那些不起作用的按钮在单击时会多次触发。如果有人能告诉我为什么会发生这种情况,我将不胜感激

// Toggle line-through todo
$('.todo-container').on('click', function(){
  $(this).toggleClass('line-through');
  console.log("fired")
})

正如Mike所评论的,您在每次按enter键时都会再次向元素添加一个新的处理程序,而不是使用


进一步解释: 当您添加如下所示的事件处理程序时,jQuery会查看DOM并将处理程序直接添加到具有todo容器类的任何元素中

一个重要的警告是,这只会将处理程序添加到页面上当前存在的元素中

当您意识到处理程序不能在新创建的(动态)元素上运行时,您看到了这样的结果

由于不太理解它为什么不起作用,您将事件绑定移动到keyup的处理程序中,从而在每次创建新元素时有效地调用绑定。这在一开始似乎是可行的,但实际上是有缺陷的,因为这再次将处理程序直接添加到具有
todo容器
类的任何元素中。包括已经从上一次调用中定义了处理程序的元素


固定一个(首选方法) 在下面的示例中,我们将绑定移回keyup处理程序外部,并使用
$(“#todos”)。在('click'、'.todo container'、
上,将侦听器附加到
'#todos'
元素(该元素始终存在于页面上)。然后,每当您在该元素内部单击时,它都会检查您单击的子元素是否具有类“todo container”如果是这样,将触发您的代码。这是事件委派。这将捕获与选择器匹配的任何动态元素上的事件

$(document).on('keypress', function(e) {
  // Add todo
  if (e.which === 13 && $('.input-field').val() != "") {
    $('#todos').prepend(todoTemplate);
    var todo = $('.todo-container');
    $('#todos').children().first().find(todo).html($('.input-field').val());
    $('.input-field').val("");
  }

})



// Remove todo
$('#todos').on('click', '.todo-container-delete', function() {
    $(this).parent().remove();
  })
  // Toggle line-through todo
$('#todos').on('click', '.todo-container', function() {
  $(this).toggleClass('line-through');
  console.log("hello")
})

修正两个更具体的目标 如果专门针对新添加的元素,则实际上可以将绑定保留在keyup处理程序中,如下所示:

$('#todos .todo-container:last').on('click', function(){
$('.todo-container').off().on('click', function(){


解决三个问题(不推荐,但可能) 如果使用.off()将处理程序从以前的元素中删除,然后再将其添加到所有元素中,则也可以将绑定保留在keyup处理程序中,如下所示:

$('#todos .todo-container:last').on('click', function(){
$('.todo-container').off().on('click', function(){

不过,我会避免使用这种方法,因为如果您没有专门针对要删除的处理程序(如何删除,请参阅文档),您正在删除应用于该元素的所有处理程序,它肯定会咬您一口

就像Mike评论的那样,您在每次按enter键时都会再次向元素添加一个新的处理程序,而不是使用


进一步解释: 当您添加如下所示的事件处理程序时,jQuery会查看DOM并将处理程序直接添加到具有todo容器类的任何元素中

一个重要的警告是,这只会将处理程序添加到页面上当前存在的元素中

当您意识到处理程序不能在新创建的(动态)元素上运行时,您看到了这样的结果

由于不太理解它为什么不起作用,您将事件绑定移动到了keyup的处理程序中,每次创建新元素时都会有效地调用绑定。起初这似乎是可行的,但实际上是有缺陷的,因为这再次将处理程序直接添加到具有
todo容器
类的任何元素中。包括已从上一次调用中定义了处理程序的元素


固定一个(首选方法) 在下面的示例中,我们将绑定移回keyup处理程序外部,并使用
$(“#todos”)。在('click'、'.todo container'、
上,将侦听器附加到
'#todos'
元素(该元素始终存在于页面上)。然后,每当您在该元素内部单击时,它都会检查您单击的子元素是否具有类“todo container”如果是这样,将触发您的代码。这是事件委派。这将捕获与选择器匹配的任何动态元素上的事件

$(document).on('keypress', function(e) {
  // Add todo
  if (e.which === 13 && $('.input-field').val() != "") {
    $('#todos').prepend(todoTemplate);
    var todo = $('.todo-container');
    $('#todos').children().first().find(todo).html($('.input-field').val());
    $('.input-field').val("");
  }

})



// Remove todo
$('#todos').on('click', '.todo-container-delete', function() {
    $(this).parent().remove();
  })
  // Toggle line-through todo
$('#todos').on('click', '.todo-container', function() {
  $(this).toggleClass('line-through');
  console.log("hello")
})

修正两个更具体的目标 如果专门针对新添加的元素,则实际上可以将绑定保留在keyup处理程序中,如下所示:

$('#todos .todo-container:last').on('click', function(){
$('.todo-container').off().on('click', function(){


解决三个问题(不推荐,但可能) 如果使用.off()将处理程序从以前的元素中删除,然后再将其添加到所有元素中,则也可以将绑定保留在keyup处理程序中,如下所示:

$('#todos .todo-container:last').on('click', function(){
$('.todo-container').off().on('click', function(){

不过,我会避免使用这种方法,因为如果您没有专门针对要删除的处理程序(如何删除,请参阅文档),您正在删除应用于该元素的所有处理程序,这肯定会让您一败涂地

看起来您正在另一个事件处理程序中运行该代码。您知道多次调用
.on
时会发生什么吗?将其放入其中似乎是唯一可行的方法,因为我们使用了.todo容器在处理程序之外无法识别。当然,因为您正在生成需要附加事件处理程序的新元素。问题是您也在将事件处理程序附加到已存在的元素。请查看@ElightedDod的答案。这是一个关于何时使用事件委派的完美示例。这是因为您正在动态添加它们ally,您需要使用event delegationIt看起来您正在另一个事件处理程序中运行该代码。您知道当您多次调用
.on
时会发生什么吗?将其放入内部似乎是唯一可行的方法,因为.todo容器在处理程序之外无法识别。当然,因为您正在生成新的elements需要将事件处理程序附加到它们。问题是您还将事件处理程序附加到了已经存在的事件处理程序。请查看@Delighted0d的答案。这是何时使用事件委派的一个完美示例。这是