首次打开Modal时出现卡顿的原因排查求助
Modal首次打开时卡顿的问题排查与修复
卡顿仅在Modal首次打开时出现。我原本推测原因是在body上绑定单个事件监听器且处理函数包含多条件判断(用于实现点击Modal外部关闭功能),但这个推测不成立。
相关代码如下:
open.addEventListener('click', (e) => { e.stopPropagation(); change(); document.body.addEventListener('click', takeInput); }); function takeInput(e) { e.stopPropagation(); let form = document.querySelector('.details_section'); let formData = new FormData(form); if (e.target.closest('.shut') || (!e.target.closest('.modal'))) { form.reset(); change(); } else if (e.target.closest('.signin')) { if (form.checkValidity()) { console.log('true') change(); form.reset(); } else { console.log('false') form.reportValidity(); } } else if (e.target.closest('.reset')) { form.reset(); } }
问题分析
- 重复绑定事件监听器:每次点击打开按钮,都会给body新增一个
takeInput监听器,首次打开虽只绑一次,但后续重复打开会导致多个监听器叠加,触发时多次执行,积累性能问题。 - 重复DOM查询:每次触发
takeInput都重新查询.details_section,首次打开时DOM刚渲染,查询开销更明显。 - 不必要的FormData创建:无论点击什么元素,都创建
FormData,但只有登录分支才可能用到,浪费性能。 - 事件冒泡处理不当:在body监听器里调用
e.stopPropagation(),会阻止其他事件正常冒泡,可能引发额外逻辑冲突。
修复方案
- 缓存DOM元素:提前获取并复用DOM节点,避免重复查询
- 避免重复绑定事件:初始化时只绑定一次body监听器,或在关闭Modal时移除监听器
- 优化事件冒泡逻辑:在Modal容器上绑定点击事件阻止冒泡,替代body监听器里的判断
- 按需创建FormData:仅在登录分支里创建FormData,减少不必要的开销
修改后的示例代码:
// 提前缓存DOM元素 const openBtn = document.querySelector('.open'); const form = document.querySelector('.details_section'); const modal = document.querySelector('.modal'); // 初始化时绑定一次body点击事件 document.body.addEventListener('click', handleModalOutsideClick); // Modal内部点击阻止冒泡,避免触发外部关闭逻辑 modal.addEventListener('click', (e) => e.stopPropagation()); openBtn.addEventListener('click', (e) => { e.stopPropagation(); toggleModal(); }); function handleModalOutsideClick(e) { if (e.target.closest('.shut') || !modal.contains(e.target)) { form.reset(); toggleModal(); } else if (e.target.closest('.signin')) { if (form.checkValidity()) { console.log('true'); // 仅在此处创建FormData const formData = new FormData(form); toggleModal(); form.reset(); } else { console.log('false'); form.reportValidity(); } } else if (e.target.closest('.reset')) { form.reset(); } } // 假设toggleModal是控制Modal显示/隐藏的函数 function toggleModal() { // 你的显示/隐藏逻辑 }
内容的提问来源于stack exchange,提问作者user19804865
相关产品推荐
相关产品推荐

