Javascript 为多个事件配置同一按钮

Javascript 为多个事件配置同一按钮,javascript,dom-events,Javascript,Dom Events,我在我的web应用程序中有一个表单按钮(纯用Vanilla Js制作),表单用于从用户那里获取数据,当单击该按钮时,数据将进入HTML表,以此类推 要编辑表格行,我已在表格列(每行)上放置了“编辑”按钮,下面附上的图片将有助于获得清晰的想法: 蓝色提交按钮命名为“addButton”,当用户点击表中特定行的“Edit”时,相应的数据显示在输入字段中,用户可以填写新的详细信息 到目前为止一切正常,现在真正的问题开始了:在用户编辑输入字段中的信息后,蓝色的提交按钮用于保存这些更改,并自动在表中显示

我在我的web应用程序中有一个表单按钮(纯用Vanilla Js制作),表单用于从用户那里获取数据,当单击该按钮时,数据将进入HTML表,以此类推

要编辑表格行,我已在表格列(每行)上放置了“编辑”按钮,下面附上的图片将有助于获得清晰的想法:

蓝色提交按钮命名为“addButton”,当用户点击表中特定行的“Edit”时,相应的数据显示在输入字段中,用户可以填写新的详细信息

到目前为止一切正常,现在真正的问题开始了:在用户编辑输入字段中的信息后,蓝色的提交按钮用于保存这些更改,并自动在表中显示更改。(这是必需的行为)

相反,所发生的情况是:表中显示修改后的行,行中生成一个具有相同详细信息的新条目(“addButton”事件侦听器执行两次,一次用于保存用户所做的更改,一次用于在行中添加新项)

我已经放置了两次此事件侦听器(相同的名称,因为我不想使用单独的按钮来保存已编辑的信息)。 为清晰起见,请查看代码:

(这是全局范围内的第一个addButton事件侦听器-用于向表中添加新条目)

对于第行中的“编辑和删除”按钮,我有:
modifyBtn
绑定到表,所以我可以用它来获得click target

(存在第二个addButton事件侦听器,用于保存更改并在表中显示输出)

因此,在编辑之后,当用户单击蓝色提交按钮时,我只希望执行
addButton
事件侦听器中的
modifyBtn
事件侦听器,
当前正在执行两个
addButton
事件侦听器。很抱歉解释得太多。

正如您可能知道的,问题在于您正在同时将多个单击侦听器分配给同一元素(您想要的行为)(您不想要的行为)。有几种方法可以解决这个问题


最快的修复 解决问题的最快方法是使用。这样,在创建设置编辑数据的第二个单击侦听器之前,可以删除上一个单击侦听器(向
info
数组添加新元素的侦听器)

在第二个click listener函数结束时,您将再次绑定第一个click listener,使行为恢复正常

此解决方案的优点
  • 这是解决问题的最快方法
  • 此解决方案的缺点
  • 取消绑定和重新绑定事件侦听器会使您很难对代码进行推理
  • 要删除事件侦听器,您需要提供原始函数(如
    .removeEventListener(“单击”,listenerFunction)
    。由于您当前使用的是,您必须将当前在单击侦听器中的函数移动到其他位置,并将其命名(这样您就可以将它们传递给
    removeEventListener
    函数
  • 实际上并不清楚在任何时候哪个事件侦听器绑定到
    addButton
  • 解决方案 我们需要将
    addButton
    的函数声明移到
    .addEventListener
    之外,并为其命名。我已将其命名为
    addItemClickHandler
    ,但您可以随意调用它:

    function addItemClickHandler(e) {
        var obj = {
            id : object.count,
            date : formatDate(inDate.value, inMonth.value),
            day : inDay.value,
            item : inItem.value,
            price : parseInt(inPrice.value),
        };
        object.info.push(obj);
        object.count += 1;
        refreshDOM();
    }
    
    addButton.addEventListener("click", addItemClickHandler);
    
    这应该是完全相同的。现在我们需要将第二个事件侦听器函数移动到它自己的命名函数中。因为我们只是从函数本身内部引用该函数的名称,我们甚至不需要将其移出,只需给它一个名称。我将给它一个
    editItemClickHandler

    addButton.removeEventListener("click", addItemClickHandler);
    addButton.addEventListener("click", function editItemClickHandler(e){
        object.info[eindex]['day'] = inDay.value;
        object.info[eindex]['date'] = formatDate(inDate.value, inMonth.value);
        object.info[eindex]['item'] = inItem.value;
        object.info[eindex]['price'] = parseInt(inPrice.value);
        refreshDOM();
    
        addButton.removeEventListener("click", editItemClickHandler);
        addButton.addEventListener("click", addItemClickHandler);
    });
    
    • 如您所见,我们首先删除侦听器
      addItemClickHandler
      ,这样当您单击“添加”按钮时,它就不会做任何事情

    • 然后我们绑定一个不同的click listener,我们给它命名为
      editItemClickHandler
      ,这样我们可以在编辑完成后删除它

    • 我们做了所有需要做的编辑

    • 最后,我们删除了我们创建的新的编辑点击监听器,并重新添加了原始的点击监听器,使功能恢复正常


    更健壮的修复

    上面的解决方案是解决问题的最快方法,但还有更可靠的方法来确保解决方案的有效性。在这个解决方案中,我将整理一些代码,使其更清晰、更易于理解

    此解决方案的优点
  • 我们不必取消绑定或重新绑定任何单击侦听器
  • 对正在发生的事情进行推理比较容易
  • 此解决方案的缺点
  • 它需要更长的时间来实现,因为它需要重构更多的代码
  • 解决方案 步骤1:跟踪我们是否正在编辑 首先,由于我们没有重新绑定单击侦听器,我们需要跟踪正在编辑的内容。让我们在
    对象
    的正下方创建一个名为
    编辑
    的对象:

    var editing = {
        mode: false,
        index: null
    };
    
    这将使我们能够跟踪是否正在编辑任何内容(
    editing.mode
    ),以及正在编辑的项目的索引是什么(
    editing.index

    步骤2:更新
    addButton
    事件侦听器以使用
    编辑对象
    接下来,我们需要修改我们的
    addButton.addEventListener
    以使用这个新的
    编辑对象:

    addButton.addEventListener("click", function(e){
        if (editing.mode) {
            var info = object.info[editing.index];
    
            info['day'] = inDay.value;
            info['date'] = formatDate(inDate.value, inMonth.value);
            info['item'] = inItem.value;
            info['price'] = parseInt(inPrice.value);
    
            editing.mode = false;
        } else {
            var obj = {
                id : object.count,
                date : formatDate(inDate.value, inMonth.value),
                day : inDay.value,
                item : inItem.value,
                price : parseInt(inPrice.value),
            };
            object.info.push(obj);
            object.count += 1;
        }
    
        refreshDOM();
    });
    
    • 如果
      editing.mode
      true
      ,当单击
      add按钮
      时,它将更新值,然后禁用
      editing.mode
      ,使其恢复到以前的状态

    • 如果
      editing.mode
      false
      ,则只需将该项添加到数组中(与之前的代码相同)

    • 无论发生什么情况,DOM都将被刷新

    步骤3:更新
    modifyBtn
    事件侦听器以使用
    编辑
    ob
    var editing = {
        mode: false,
        index: null
    };
    
    addButton.addEventListener("click", function(e){
        if (editing.mode) {
            var info = object.info[editing.index];
    
            info['day'] = inDay.value;
            info['date'] = formatDate(inDate.value, inMonth.value);
            info['item'] = inItem.value;
            info['price'] = parseInt(inPrice.value);
    
            editing.mode = false;
        } else {
            var obj = {
                id : object.count,
                date : formatDate(inDate.value, inMonth.value),
                day : inDay.value,
                item : inItem.value,
                price : parseInt(inPrice.value),
            };
            object.info.push(obj);
            object.count += 1;
        }
    
        refreshDOM();
    });
    
    <td><a href="#" data-id={{id}} data-action="edit">Edit</a> | <a href="#" data-id={{id}} data-action="delete">Delete</a></td>
    
    modifyBtn.addEventListener('click', function(e){
        e.preventDefault();
    
        var el = e.target;
        var id = parseInt(el.dataset.id);
        var index = object.info.findIndex(item => item.id === id);
        var info = object.info[index];
        var action = el.dataset.action;
    
        if (action === "edit") {
            editing.mode = true;
            editing.index = index;
    
            inDay.value = info['day'];
            inDate.value = parseInt(info['date'].substr(0,2));
            inMonth.value = info["date"].substr(4);
            inItem.value = info['item'];
            inPrice.value = info['price'];
        }
    
        if (action === "delete") {
            object.info.splice(index, 1);
        }
    
        refreshDOM();
    });
    
    <h2 id="form-header">Add Item</h2>
    
    formHeader = getElement('form-header');
    
    formHeader.textContent = editing.mode ? "Edit Item" : "Add Item";