自定义DOM函数致表单二次提交时页面重载问题排查
问题分析与解决方案:表单二次提交时页面重载
你遇到的这个二次提交页面重载的问题,罪魁祸首就是toggleDOM函数里的document.body.innerHTML +=操作!
问题根源
当你使用innerHTML +=给body添加元素时,浏览器会把当前body的所有HTML重新解析一遍,再生成全新的DOM元素。这就意味着原来的表单元素会被完全替换成新元素,而你之前通过addEventListener绑定的submit事件监听,是绑定在旧表单元素上的——新生成的表单根本没有这个事件监听。
第一次提交时,事件监听还在,e.preventDefault()能正常阻止页面重载;但第一次调用toggleDOM('.loading', true)后,表单被重新创建,事件监听直接丢失了。第二次点击提交按钮时,没有代码阻止默认的表单提交行为,页面自然就重载了。
另外原toggleDOM函数还有个语法错误:拼接HTML时标签闭合写错了(比如'<div id="' + newDom + '></div>'写成了<div id="' + newDom + '></div>的不完整形式),这也会导致HTML解析异常。
修复后的toggleDOM函数
我们改用原生DOM API创建元素,避免操作innerHTML带来的DOM重绘和事件丢失问题:
$.fn.toggleDOM = (domName, b) -> # 解析选择器的类型(类/ID)和名称 match = domName.match(/^([.#])(\w+)$/) if !match return [_, domType, newDom] = match if b # 创建新元素并追加到body,不触发整体DOM重绘 div = document.createElement('div') if domType == '#' div.id = newDom else div.classList.add(newDom) document.body.appendChild(div) else # 找到目标元素并移除 if domType == '#' elem = document.getElementById(newDom) else elem = document.getElementsByClassName(newDom)[0] if elem elem.remove()
修复说明
- 用
document.createElement创建元素,再通过appendChild添加到body,不会破坏现有DOM结构和已绑定的事件监听; - 移除元素时直接定位目标元素调用
remove(),避免操作innerHTML的副作用; - 修复了原函数中HTML拼接的语法错误,避免解析异常。
修改后再测试表单提交,不管第一次还是第二次,e.preventDefault()都会正常生效,页面不会重载,同时loading spinner的功能也能正常工作。
内容的提问来源于stack exchange,提问作者P. Nick
相关产品推荐
相关产品推荐

