使用 addEventListener 和函数时避免重复代码的最佳方法

Best way to avoid repeating code when using addEventListener and functions

提问人:Joel del Pilar 提问时间:12/12/2022 更新时间:12/12/2022 访问量:63

问:

我在编码方面很新,目前正在研究前端开发。我正在学习 JS 的第 5 周,并且遇到了使用 Typescript 创建待办事项列表的挑战。

当我在我的应用程序中创建任务时,它有一个复选框和一个“垃圾箱”按钮。垃圾桶按钮的标识非常清晰,复选框将在“选中”时将任务放在列表中的最后。

在创建事件侦听器时,我注意到了一些重复的代码。因此,我找到了一种将事件侦听器添加到多个元素的方法,但我无法思考如何调用与单击的内容相对应的不同函数。

这就是我找到一种将事件侦听器添加到每个元素的方法。但是从这里开始,我如何根据点击的内容调用函数?

    document.querySelectorAll('.add-click-listener').forEach(item => {
        item.addEventListener('click',  event => {

        })
    })

这是从头开始的代码

    let checkbox = Array.from(document.querySelectorAll('.hidden-checkbox'));
    checkbox.forEach((item) => {
        item.addEventListener('click', checkboxStatusShift);
    });
    
    let trashBtn = Array.from(document.querySelectorAll('.trash-btn')); 
    trashBtn.forEach((item) => {
        item.addEventListener('click', deleteTask);
    });

这将是“回收”任务的功能:

function deleteTask(event: any) {
    const index = (event.currentTarget);
    const buttonId = index.id?.replace('remove-', '');
    const currentTask = todoDatabase.filter((object) => object.id === buttonId)[0];
    const currentTaskId = currentTask.id;
  
    console.log(buttonId);
    console.log(currentTaskId);
    

    if (buttonId == currentTaskId) {
        todoDatabase.splice(0, 1);
        printTodoList();
    }

}   

我还没有启动复选框函数的代码。

非常感谢我能得到的任何提示。

数组 TypeScript 函数 DOM 事件

评论

0赞 Thomas 12/12/2022
1. -> 数组#find()。2. 谨慎使用匿名函数作为事件处理程序。您将永远无法从该目标中删除该事件处理程序。这可能没问题,但以后也可能会咬你的屁股。array.filter(...)[0]
0赞 Joel del Pilar 12/12/2022
嗨,托马斯!我明白你的吗 1.你的意思是我应该切换过滤器来查找吗?我想尽可能跳过匿名函数,问题是我不知道如何让我重构的 addEventlistener 根据点击的内容调用两个不同的函数?

答:

0赞 Oro 12/12/2022 #1

根据我的经验,您可以使用事件委派模式来避免重复代码。您必须将事件侦听器附加到父元素,然后在处理程序中检查它是否与子元素匹配。单击子项的事件将冒泡,因此您将抓住它。在代码中,它将如下所示:

document.querySelector('#parent-element').addEventListener('click', function(e) {
  if (e.target && e.target.matches('.child-element')) {
    // do your stuff here
  }
});

评论

0赞 Joel del Pilar 12/12/2022
嗨,奥罗!这个我不知道,在你的例子中,“function(e)”是匿名的吗?无论如何,坦克你的回应,我会试一试。
0赞 Oro 12/12/2022
是的,在我的示例中它是匿名的,但您可以将其设置为变量或命名函数,然后如果需要,您将能够删除侦听器
0赞 Andrey Zinoviev 12/12/2022 #2

可以绑定到复选框所在的根元素,并处理触发事件的目标元素。

如果 HTML 如下所示:

<div id="app">
  <div class="checkboxes">
    <input id="1" type="checkbox" /><label for="1">Checkbox 1</label>
    <input id="2" type="checkbox" /><label for="2">Checkbox 2</label>
    <input id="3" type="checkbox" /><label for="3">Checkbox 3</label>
  </div>
</div>

示例 JS 代码如下所示:

const root = document.getElementsByClassName('checkboxes')[0];
root.addEventListener('click', function (event) {
  const target = event.target;

  if (target.tagName == 'INPUT') {
    console.log(target.id);
    console.log(target.checked);
  }
});

使用类名“checkboxes”将单击事件绑定到根 div,并处理触发事件的确切人员。

如果你可以使用 Jquery,那么函数 https://api.jquery.com/on 也可以做同样的事情on

$(div.checkboxes).on("click", ".checkbox", function(event){})

评论

0赞 Joel del Pilar 12/12/2022
嗨,安德烈!感谢您的回复!我的复选框是由 JS 呈现的。每个“任务”都是一个 div,其中包含一个输入类型复选框,然后是一个标签和一个按钮元素。在这种情况下,示例代码是否仍然适用?
0赞 Andrey Zinoviev 12/12/2022
我想是的。你可以在这里试试 stackblitz.com/edit/js-sthdna?file=index.js 只需将 html 标记替换为您自己的标记即可。
1赞 Joel del Pilar 12/12/2022 #3

感谢所有的回复,这为我指明了正确的方向,我让它按预期工作,结果是以下代码:

    document.querySelectorAll('.add-click-listener').forEach(item => {
        item.addEventListener('click',  (event: any) => {
            const thisWasClicked = event.currentTarget;
            let trashBtn = Array.from(document.querySelectorAll('.trash-btn'));

            const filterTrashBtn: any = trashBtn.find((btn) => btn.id === thisWasClicked.id);
            const findTask = trashBtn.indexOf(filterTrashBtn);

            if (filterTrashBtn?.id == thisWasClicked.id) {
                todoDatabase.splice(findTask, 1);
                printTodoList();

            }
                        
        });
        
    });

现在,我可以使用另一个 if 和一些变量等为我的复选框编写代码。