模态框重复绑定事件监听器致请求倍增问题求助
模态框重复打开后请求次数倍增问题解决
问题描述
我制作了一个用于修改卡片属性(名称、描述和所属公司)的模态框,功能基本正常,但不刷新页面重复打开模态框时,请求次数会成倍增加(两次、三次甚至更多),只有刷新页面能暂时解决,但这并非合理方案。
关键代码片段
JavaScript 代码
function getAllDepartmentHandleButton() { const allDeleteButtons = document.querySelectorAll('.departmentContainer__content--card') allDeleteButtons.forEach(e => { e.addEventListener('click', (event) => { if(event.target.classList.value == 'remove') { showRemoveDepartmentModal(event.target.id, event.target.alt) } else if(event.target.classList.value == 'edit') { showEditDepartmentModal(event.target.id) } }) }) } async function showEditDepartmentModal(departmentId) { let companyToEditid = 0 const allDepartments = await getAllDepartments() const editModal = document.querySelector('.editDepartmentModal') const closeBtn = document.querySelector('.editDepartmentModal__container > img') const nameInput = document.querySelector('.editDepartmentModal__container--departmentName') const descriptionInput = document.querySelector('.editDepartmentModal__container--departmentDescription') const selectedCompanyInput = document.querySelector('.editDepartmentModal__container--company > span') const placeToAppend = document.querySelector('.editDepartmentModal__container--list') const showCompanyOptionsButton = document.querySelector('.editDepartmentModal__container--company') const dialogCompanyOptions = document.querySelector('.editDepartmentModal__container > dialog') const allCompanies = await getAllCompanies() const buttonSaveAlterations = document.querySelector('.editDepartmentModal__container--button') allCompanies.forEach(e => { placeToAppend.insertAdjacentHTML('beforeend', ` <li id="${e.uuid}">${e.name}</li> `) }) editModal.showModal() const selectedCompany = allDepartments.find(e => { if (e.uuid == departmentId) { return e } }) closeBtn.addEventListener('click', () => { editModal.close() }) nameInput.value = selectedCompany.name descriptionInput.value = selectedCompany.description selectedCompanyInput.innerText = selectedCompany.companies.name selectedCompanyInput.id = departmentId showCompanyOptionsButton.addEventListener('click', ()=> { if(dialogCompanyOptions.open) { dialogCompanyOptions.close() } else { dialogCompanyOptions.show() } }) placeToAppend.addEventListener('click', (event) => { companyToEditid = event.target.id selectedCompanyInput.innerText = event.target.innerText dialogCompanyOptions.close() }) buttonSaveAlterations.addEventListener('click', () => { if(nameInput.value == '' || descriptionInput.value == '') { alert('vazio') } else { editDepartmentFunction(nameInput.value, descriptionInput.value, companyToEditid) editModal.close() } }) } function editDepartmentFunction(test1, test2, test3) { console.log(test1, test2,test3) }
HTML 代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="../styles/globalStyles.css"> <link rel="stylesheet" href="../styles/indexStyles.css"> <link rel="stylesheet" href="../styles/AdminPageStyling copy.css"> <link rel="stylesheet" href="../styles/adminPagesModal.css"> </head> <body> <header> <div class="titleAndMenuIcon"> <span><span class="titleAndMenuIcon__bulelt">• </span>Kenzie Empresas</span> <button>Logout</button> </div> </header> <main> <div class="departmentContainer"> <div class="departmentContainer__header"> <span class="departmentContainer__header--title">Departamentos</span> <div class="departmentContainer__header--companiesSelect"> <span class="">Selecionar Empresa</span> <img src="../files/down-arrow-svgrepo-com.svg" alt=""> </div> <dialog class="departmentContainer__header--companiesModal"> <ul> </ul> </dialog> <div class="departmentContainer__header--create"><img src="../files/plusIcon.svg" alt=""><span>Criar</span></div> </div> <div class="departmentContainer__content"> </div> </div> <div class="userContainer"> <div class="userContainer__header"> <span class="userContainer__header--title">Usuários Cadastrados</span> </div> <div class="userContainer__content"> </div> </div> </main> <dialog class="createDepartmentModal"> <div class="createDepartmentModal__container"> <img src="../files/closebtnsvg.svg" alt=""> <span class="createDepartmentModal__container--title">Criar Departemento</span> <input type="text" class="createDepartmentModal__container--departmentName" placeholder="Nome do Departamento"> <input type="text" class="createDepartmentModal__container--departmentDescription" placeholder="Descrição"> <div class="createDepartmentModal__container--company"> <span>Selecionar Empresa</span> <img src="../files/down-arrow-svgrepo-com.svg" alt=""> </div> <dialog class="createDepartmentModal__container--company__modal"> <ul class="createDepartmentModal__container--company__modal--container"> </ul> </dialog> <span class="createDepartmentModal__container--button">Criar Departamento</span> </div> </dialog> <dialog class="removeDepartmentModal"> <div class="removeDepartmentModal__container"> <span>mensagem aqui</span> <div>Continuar</div> <img src="../files/closebtnsvg.svg" alt=""> </div> </dialog> <dialog class="editDepartmentModal"> <div class="editDepartmentModal__container"> <dialog><ul class="editDepartmentModal__container--list"></ul></dialog> <img src="../files/closebtnsvg.svg" alt=""> <span class="editDepartmentModal__container--title">Editar Departamento</span> <input type="text" class="editDepartmentModal__container--departmentName" placeholder="Novo Nome do Departamento"> <input type="text" class="editDepartmentModal__container--departmentDescription" placeholder="Nova Descrição"> <div class="editDepartmentModal__container--company"> <span>Selecionar Empresa</span> <img src="../files/down-arrow-svgrepo-com.svg" alt=""> </div> <dialog class="editDepartmentModal__container--company__modal"> <ul class="editDepartmentModal__container--company__modal--container"> </ul> </dialog> <span class="editDepartmentModal__container--button">Salvar Alterações</span> </div> </dialog> </body> <script src="../scripts/AdminPageScript.js"></script> </html>
问题原因
- 重复绑定事件监听器:每次调用
showEditDepartmentModal时,都会给关闭按钮、保存按钮、公司选择按钮等DOM元素绑定新的事件监听器。第一次打开绑定1个,第二次打开再绑定1个,点击时就会触发多次请求/操作。 - 重复插入DOM元素:每次打开模态框都会往公司列表中追加新的
<li>选项,导致列表越来越长,同时也会累积点击事件。
解决方案
1. 重构事件绑定逻辑,只初始化一次
将模态框的所有事件绑定移到页面初始化阶段,只执行一次,避免重复绑定。打开模态框时仅负责填充数据,而非绑定事件。
2. 清空旧数据再填充
每次打开模态框前,清空公司列表和输入框的旧数据,避免残留内容。
3. 使用事件委托优化卡片点击监听
将卡片的点击事件绑定到父容器上,而非每个卡片单独绑定,适合动态生成的卡片,同时避免重复绑定。
修改后的代码示例
// 初始化模态框事件,仅执行一次 function initEditModalEvents() { const editModal = document.querySelector('.editDepartmentModal') const closeBtn = document.querySelector('.editDepartmentModal__container > img') const nameInput = document.querySelector('.editDepartmentModal__container--departmentName') const descriptionInput = document.querySelector('.editDepartmentModal__container--departmentDescription') const selectedCompanyInput = document.querySelector('.editDepartmentModal__container--company > span') const placeToAppend = document.querySelector('.editDepartmentModal__container--list') const showCompanyOptionsButton = document.querySelector('.editDepartmentModal__container--company') const dialogCompanyOptions = document.querySelector('.editDepartmentModal__container > dialog') const buttonSaveAlterations = document.querySelector('.editDepartmentModal__container--button') let currentDepartmentId = '' let companyToEditid = 0 // 关闭按钮事件 closeBtn.addEventListener('click', () => { editModal.close() resetEditModalState() }) // 显示/隐藏公司选项 showCompanyOptionsButton.addEventListener('click', () => { dialogCompanyOptions.open ? dialogCompanyOptions.close() : dialogCompanyOptions.show() }) // 选择公司 placeToAppend.addEventListener('click', (event) => { if(event.target.tagName === 'LI') { companyToEditid = event.target.id selectedCompanyInput.innerText = event.target.innerText dialogCompanyOptions.close() } }) // 保存修改 buttonSaveAlterations.addEventListener('click', async () => { if(!nameInput.value || !descriptionInput.value) { alert('vazio') return } editDepartmentFunction(nameInput.value, descriptionInput.value, companyToEditid, currentDepartmentId) editModal.close() resetEditModalState() }) // 重置模态框状态 function resetEditModalState() { nameInput.value = '' descriptionInput.value = '' selectedCompanyInput.innerText = 'Selecionar Empresa' selectedCompanyInput.id = '' companyToEditid = 0 placeToAppend.innerHTML = '' } // 填充模态框数据的方法 return { fillData: async (departmentId) => { currentDepartmentId = departmentId const allDepartments = await getAllDepartments() const allCompanies = await getAllCompanies() const selectedDepartment = allDepartments.find(e => e.uuid === departmentId) // 清空列表再插入新选项 placeToAppend.innerHTML = '' allCompanies.forEach(e => { placeToAppend.insertAdjacentHTML('beforeend', `<li id="${e.uuid}">${e.name}</li>`) }) // 填充现有数据 nameInput.value = selectedDepartment.name descriptionInput.value = selectedDepartment.description selectedCompanyInput.innerText = selectedDepartment.companies.name companyToEditid = selectedDepartment.companies.uuid selectedCompanyInput.id = selectedDepartment.companies.uuid editModal.showModal() } } } // 初始化模态框管理对象 const editModalManager = initEditModalEvents() // 修改显示模态框的函数,仅调用填充数据方法 async function showEditDepartmentModal(departmentId) { await editModalManager.fillData(departmentId) } // 改用事件委托监听卡片点击,避免重复绑定 function getAllDepartmentHandleButton() { document.querySelector('.departmentContainer__content').addEventListener('click', (event) => { const target = event.target if(target.classList.contains('remove')) { showRemoveDepartmentModal(target.id, target.alt) } else if(target.classList.contains('edit')) { showEditDepartmentModal(target.id) } }) } // 页面加载完成后初始化事件 document.addEventListener('DOMContentLoaded', () => { getAllDepartmentHandleButton() }) function editDepartmentFunction(name, desc, companyId, departmentId) { console.log(name, desc, companyId, departmentId) // 这里执行实际的请求逻辑 }
内容的提问来源于stack exchange,提问作者okimstartingtocode
相关产品推荐
相关产品推荐

