BulmaModal模态框JS代码仅可临时生效问题排查问询
问题原因
- 核心原因1:状态切换方法不匹配,多次触发会导致状态混乱
你在show()方法中给html元素加is-clipped类用的是classList.add(),但是close()方法中移除的时候用的是classList.toggle(),同时两个方法控制模态框显示隐藏的is-active类都用了toggle():- 如果因为重复绑定事件等原因,一次点击触发了两次
show(),is-active会被切换两次回到隐藏状态,看起来点了没反应 - 如果多次打开模态框,
is-clipped会被添加多次,关闭时一次toggle()只会删除一个,残留的is-clipped会导致页面始终无法滚动
- 如果因为重复绑定事件等原因,一次点击触发了两次
- 核心原因2:事件监听器重复绑定,没有做去重处理,这就是CodePen上临时生效后失效的直接原因
CodePen保存后会触发热重载,重新执行一遍JS代码,每次执行都会给按钮、模态框关闭元素新增一次点击事件监听器,旧的监听器不会自动清除。几次热重载之后,点一次按钮就会触发N次show(),如果N是偶数,is-active切换偶数次就等于没变化,看起来就失效了。 - 补充本地运行失败原因:如果是本地直接打开HTML文件无法运行,是因为代码用了
type="module"加载JS,浏览器的file协议不支持跨域加载ES模块,只需要在项目目录下启动一个本地静态服务(比如vscode的Live Server插件、执行npx serve命令)再访问即可。
修复方案
- 把
show()、close()里的toggle换成明确的add和remove,避免状态受调用次数影响:
show() { this.modal.classList.add("is-active"); // 替换toggle为add this.html.classList.add("is-clipped"); this.onShow(); } close() { this.modal.classList.remove("is-active"); // 替换toggle为remove this.html.classList.remove("is-clipped"); // 替换toggle为remove this.onClose(); }
- 绑定事件前先移除旧的监听器,避免重复绑定:
给事件回调加命名,不要用匿名函数,方便后续移除:
openEvent() { // 先移除可能存在的旧监听器 this.button.removeEventListener("click", this.openHandler); this.openHandler = (e) => { e.preventDefault(); this.show(); }; this.button.addEventListener("click", this.openHandler); } closeEvents() { const closeElements = this.modal.querySelectorAll(".modal-background, .modal-close"); closeElements.forEach((element) => { // 先移除可能存在的旧监听器 element.removeEventListener("click", element.closeHandler); element.closeHandler = (e) => { e.preventDefault(); this.close(); }; element.addEventListener("click", element.closeHandler); }); }
内容的提问来源于stack exchange,提问作者alain_invasion
相关产品推荐
相关产品推荐

