JS根据div class判断遮罩状态新增DOM元素条件失效问题
实现目标
基于「页面遮罩层处于隐藏状态」的判断条件,满足条件时向DOM中新增指定元素。
遮罩层参考HTML结构
<div id="mobile-start-container" class="fn-npnxnanbnsnfns01001000001" style="display: none;"> <div class="mobile-start-overlay shown" role="dialog" aria-modal="true" aria-labelledby="mobile-start-title" data-reactid=".0"> <div class="mobile-load-title-overlay" style="opacity:0;" data-reactid=".0.0"> <div class="mobile-load-title" id="mobile-start-title" data-reactid=".0.0.0">FORMATION AU PROGRAMME PRIMAIRE</div> </div> <div data-reactid=".0.4"> <div class="mobile-start-resume-text" data-reactid=".0.4.0"><button aria-label="Reprendre" tabindex="0" style="font-size:100%;border-radius:30px;" data-reactid=".0.4.0.0">Reprendre</button></div> <button class="restart" aria-label="Redémarrer" tabindex="0" data-reactid=".0.4.1"> <svg class="cs-icon" preserveAspectRatio="none" x="0px" y="0px" width="13px" height="15.75px" focusable="false" tabindex="-1" data-reactid=".0.4.1.0"> <path fill="#FFFFFF" transform="scale(1, 1) translate(0, 0)" stroke="none" d=" M 10.95 8.75 Q 11 9 11 9.25 10.95 11.15 9.7 12.4 8.4 13.7 6.5 13.75 4.6 13.7 3.3 12.4 2.05 11.15 2 9.25 2.05 7.3 3.3 6.05 4.398828125 4.998828125 6 4.75 L 6 6.9 Q 6.05 7.75 6.85 7.35 L 11.35 4.3 Q 11.7 4.05 11.7 3.75 11.7 3.45 11.35 3.2 L 6.85 0.15 Q 6.05 -0.3 6 0.6 L 6 2.75 Q 3.4517578125 3.001171875 1.8 4.75 0.05 6.6 0 9.25 0.05 12 1.9 13.85 3.75 15.65 6.5 15.75 9.25 15.65 11.1 13.85 12.95 12 13 9.25 13 9 13 8.75 L 10.95 8.75 Z" data-reactid=".0.4.1.0.0"></path> </svg> <div class="restart-text" style="color:white;display:inline-block;padding-left:1em;transform:translateY(-3px);font-size:13px;" data-reactid=".0.4.1.1">Redémarrer</div> </button> </div> <div class="mobile-start-course-title" style="font-size: 20.28px;" data-reactid=".0.5">FORMATION AU PROGRAMME PRIMAIRE</div> </div> </div>
原有问题脚本
document.body.onload = addElement; function addElement() { var overlayContainer = document.getElementById("mobile-start-container"); console.log(overlayContainer); var divOverlay = document.getElementsByClassName("mobile-start-overlay")[0]; console.log(divOverlay); if (divOverlay.classList.contains('shown')) { console.log("overlay is shown so don't display the button"); } else { // Create new Button element var newButton = document.createElement("button"); // add class to the new Button newButton.className = "question-btn"; // add SVG tag inside Button var newSvg = document.createElement("svg"); // add class to svg tag newSvg.className = "svg-icon"; // fill svg element with my shape var svgContent = document.createElementNS("http://www.w3.org/2000/svg", 'path'); svgContent.setAttribute("d", "M 0 0 L 10 10"); svgContent.style.stroke = "#fff"; svgContent.style.strokeWidth = "1px"; newSvg.appendChild(svgContent); // add svg node to created button newButton.appendChild(newSvg); // add new button somewhere else in DOM var currentDiv = document.getElementById('nav-controls'); document.body.insertBefore(newButton, currentDiv); console.log(newButton); } }
现存问题
- 核心故障:条件判断逻辑不生效,无论遮罩层是显示(包含
shown类)还是隐藏状态,新增按钮都会始终被渲染 - 次要问题:svg标签内的path无法正常显示(暂不优先处理)
故障原因
- 触发时机错误:遮罩层由React渲染,
body.onload触发时React可能还未完成组件挂载,仅在页面加载完成时做一次判断,无法捕获后续遮罩层显隐切换时的类名、样式变化,导致判断结果和实际状态不一致。 - 判断维度不全:仅校验了内层
.mobile-start-overlay的shown类,未校验外层容器#mobile-start-container的display: none样式,而外层容器的行内样式才是控制遮罩整体显隐的关键属性。 - SVG创建API错误:创建SVG元素必须使用带SVG命名空间的
createElementNS方法,原有代码中用createElement创建svg标签,会导致浏览器将其识别为普通HTML元素,内部path无法正常渲染。 - 缺少重复渲染校验:没有判断按钮是否已经存在于DOM中,逻辑触发时会重复插入元素。
修复后代码
// 初始化标记,避免重复绑定监听 let hasInitOverlayWatch = false; function handleOverlayStatusChange() { const overlayContainer = document.getElementById("mobile-start-container"); const divOverlay = document.querySelector(".mobile-start-overlay"); const existBtn = document.querySelector(".question-btn"); const navContainer = document.getElementById('nav-controls'); // 必要DOM未挂载时直接跳过本次判断 if (!overlayContainer || !divOverlay || !navContainer) return; // 遮罩显示判定规则:外层容器未设置display:none + 内层遮罩带shown类 const isOverlayShown = !overlayContainer.style.display.includes('none') && divOverlay.classList.contains('shown'); if (isOverlayShown) { // 遮罩显示时移除已插入的按钮 if (existBtn) existBtn.remove(); console.log("overlay is shown so don't display the button"); } else { // 遮罩隐藏时,按钮不存在才插入,避免重复渲染 if (!existBtn) { // 创建按钮 const newButton = document.createElement("button"); newButton.className = "question-btn"; // 修复SVG渲染问题:所有SVG相关元素统一使用SVG命名空间创建 const svgNS = "http://www.w3.org/2000/svg"; const newSvg = document.createElementNS(svgNS, "svg"); newSvg.setAttribute('width', '16'); newSvg.setAttribute('height', '16'); newSvg.setAttribute('viewBox', '0 0 10 10'); newSvg.className = "svg-icon"; const svgContent = document.createElementNS(svgNS, 'path'); svgContent.setAttribute("d", "M 0 0 L 10 10"); svgContent.style.stroke = "#fff"; svgContent.style.strokeWidth = "1px"; newSvg.appendChild(svgContent); newButton.appendChild(newSvg); // 插入到指定DOM位置 document.body.insertBefore(newButton, navContainer); console.log("insert button success", newButton); } } } function initOverlayWatch() { if (hasInitOverlayWatch) return; hasInitOverlayWatch = true; // 初始化时先执行一次状态判断 handleOverlayStatusChange(); // 监听DOM属性变化,适配React异步渲染、遮罩动态切换的场景 const observer = new MutationObserver(() => { handleOverlayStatusChange(); }); observer.observe(document.body, { attributes: true, subtree: true, // 只监听类名、样式变化,减少性能消耗 attributeFilter: ['class', 'style'] }); } // 兼容不同页面加载状态,初始化监听 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initOverlayWatch); } else { initOverlayWatch(); }
内容的提问来源于stack exchange,提问作者G. Delvigne
相关产品推荐
相关产品推荐

