模态窗口关闭时触发Uncaught TypeError错误的修复求助
问题修复:模态窗口关闭时的TypeError错误(保留动画效果)
我帮你揪出问题根源啦!这个Uncaught TypeError: Cannot read property 'remove' of undefined错误主要踩了几个JavaScript常见的坑,咱们一步步把它修好,同时保留你需要的动画效果:
问题核心原因
- 作用域泄漏:
setTimeout是异步执行的,当它触发时,外部的modal变量已经失效,导致访问modal.style报错。 - 错误的遍历方式:用
for...in遍历modals数组会把数组的原型属性也包含进来,遍历到非DOM元素时自然找不到classList。 - 重复的状态修改:关闭逻辑里两次执行
open_modals.pop(),还错误地移除所有模态的动画类,导致模态栈状态混乱。
修复后的完整代码
HTML部分
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <!-- Trigger/Open The Modal --> <a href="#myModal1" class="modal-button">• Click Me</a> <!-- The Modal --> <div id="myModal1" class="modal"> <!-- Modal content --> <div class="modal-content"> <div class="modal-header"> <span class="close">×</span> <div class="headertext"> <p>Modal Header</p> </div> </div> <div class="modal-body"> <img class="pic" src="https://drive.google.com/thumbnail?id=108ZLeoIfNkKODfRbLuPWpmXRl0gH9qkD"> <div class="bodytext"> <h2 class="modal-button" href="#myModal2">Enable Second Modal Window by tapping on this text</h2> </div> </div> </div> </div> <div id="myModal2" class="modal"> <!-- Modal content --> <div class="modal-content"> <div class="modal-header"> <span class="close">×</span> <div class="headertext"> <p>Modal Header 2</p> </div> </div> <div class="modal-body"> <img class="pic" src="https://drive.google.com/thumbnail?id=108ZLeoIfNkKODfRbLuPWpmXRl0gH9qkD"> <div class="bodytext"> <h2>You have opened modal window no.2</h2> </div> </div> </div> </div>
CSS部分
@import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap'); /* The Modal (background) */ .modal { box-sizing: border-box; font-family: 'Quicksand', sans-serif; display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ padding-top: 0.1875em; /* Location of the box */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0, 0, 0); /* Fallback color */ background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */ } /* Modal Content */ .modal-content { color: white; position: relative; background-color: #171B20; margin: auto; padding: 0; border: 0.0625em solid #888; width: 97%; box-shadow: 0 0.25em 0.5em 0 rgba(0, 0, 0, 0.2), 0 0.375em 1.25em 0 rgba(0, 0, 0, 0.19); -webkit-animation-name: animatetop; -webkit-animation-duration: 0.4s; animation-name: animatetop; animation-duration: 0.4s; } /* Add Animation */ @-webkit-keyframes animatetop { from { top: -300px; opacity: 0; } to { top: 0; opacity: 1; } } @keyframes animatetop { from { top: -300px; opacity: 0; } to { top: 0; opacity: 1; } } @-webkit-keyframes animateBottom { from { top: 0px; opacity: 1; } to { top: 500px; opacity: 0; } } @keyframes animateBottom { from { top: 0px; opacity: 1; } to { top: 300px; opacity: 0; } } .modal-content-active { -webkit-animation-name: animateBottom; -webkit-animation-duration: 0.4s; animation-name: animateBottom; animation-duration: 0.4s; } /* The Close Button */ .close { color: #F0B823; float: right; font-size: 9vw; font-weight: bold; position: absolute; right: 0.25em; top: -0.25em; } .close:hover, .close:focus { color: #fff; text-decoration: none; cursor: pointer; } .modal-header { padding: 0.125em 1em; background-color: #171B20; color: #F0B823; } .modal-body {} .modal-button { font-family: 'Quicksand', sans-serif; background-color: #171B20; border: none; color: white; padding: 0.248em 0.496em; text-align: left; text-decoration: none; display: inline-block; font-size: 7vw; margin: 0.124em 0.062em; -webkit-transition-duration: 0.4s; /* Safari */ transition-duration: 0; cursor: pointer; width: auto; } .modal-button:hover { background-color: #171B20; color: #F0B823; } .pic { margin: auto; display: block; height: auto; width: 50vh; } .headertext { font-family: 'Quicksand', sans-serif; display: block; text-align: center; font-size: 6.50vw; } .bodytext { font-size: 3.90vw; font-family: 'Quicksand', sans-serif; display: block; padding: 0.625em 0.9375em; } p { display: block; margin: 0; }
JavaScript部分
let open_modals = []; $(function () { // Get all modal buttons const btns = document.querySelectorAll(".modal-button"); // All page modals const modals = document.querySelectorAll('.modal'); // Get all close buttons const spans = document.getElementsByClassName("close"); // Open modal logic btns.forEach(btn => { btn.onclick = function (e) { e.preventDefault(); const targetModalId = e.target.getAttribute("href"); const modal = document.querySelector(targetModalId); if (modal) { modal.style.display = "block"; // 确保打开时重置动画类 modal.querySelector('.modal-content').classList.remove('modal-content-active'); open_modals.push(modal.id); } } }); // 封装关闭顶层模态框的逻辑 const closeTopModal = () => { if (open_modals.length === 0) return; const topModalId = open_modals[open_modals.length - 1]; const topModal = document.getElementById(topModalId); if (!topModal) return; // 添加关闭动画类 const modalContent = topModal.querySelector('.modal-content'); modalContent.classList.add('modal-content-active'); // 动画结束后隐藏模态框并清理状态 setTimeout(() => { topModal.style.display = "none"; modalContent.classList.remove('modal-content-active'); open_modals.pop(); }, 400); }; // 点击关闭按钮触发关闭 Array.from(spans).forEach(span => { span.onclick = closeTopModal; }); // 点击模态背景触发关闭 window.onclick = function (event) { if (event.target.classList.contains('modal')) { closeTopModal(); } }; })
关键修复细节
- 作用域优化:用
const/let声明变量,避免全局泄漏,同时在封装的closeTopModal函数中保存目标模态框,确保setTimeout能正确访问到元素。 - 正确遍历元素:用
forEach替代for...in和普通for循环,只遍历DOM元素,避免无效属性干扰。 - 动画逻辑统一:把关闭逻辑封装成独立函数,统一处理动画添加、延时隐藏和状态清理,避免重复代码。
- 精准DOM操作:只对当前关闭的模态框内容添加/移除动画类,不会影响其他激活的模态框。
- 状态正确维护:只在动画结束后执行一次
open_modals.pop(),确保模态栈的状态始终准确。
这样修复后,逐层打开/关闭的功能正常,动画效果保留,控制台也不会再报错啦!
内容的提问来源于stack exchange,提问作者Badal Singh
相关产品推荐
相关产品推荐

