借助Google Tag Manager(JS)实现弹窗同会话不再重复弹出
问题解决:GTM弹窗会话内仅触发一次及相关Bug修复
问题背景
在Google Tag Manager(GTM)中配置了弹窗脚本,设置两个独立触发条件:30秒后通过自定义代码向data layer推送timer_elapsed事件触发、页面滚动50%时通过GTM Scroll Depth触发器触发。测试发现:
- 弹窗在30秒显示并关闭后,滚动至页面50%位置会再次弹出
- 二次弹出的弹窗无法关闭
{{DL - locale}}数据层变量定义的翻译功能失效
需求:同一用户会话内,弹窗无论通过哪个触发条件显示后,不再重复出现。
问题根源
- 会话标记逻辑漏洞:原脚本仅在弹窗显示时标记会话状态,但未确保GTM多次触发脚本时能正确读取状态
- 事件绑定冲突:HTML中
onclick="closePopup()"与JS中addEventListener重复绑定,二次触发时函数作用域异常导致关闭失效 - 初始状态未隐藏:弹窗默认未设置隐藏,导致脚本执行时显示判断逻辑出错
- 变量传递不稳定:GTM多次触发时,
{{DL - locale}}变量未被正确注入到二次执行的脚本中
修改后的完整代码
JavaScript代码
// 检查弹窗是否已在当前会话中触发过 function hasPopupBeenTriggered() { return sessionStorage.getItem('popupTriggered') === 'true'; } // 标记弹窗已触发 function markPopupAsTriggered() { sessionStorage.setItem('popupTriggered', 'true'); } // 关闭弹窗 function closePopup() { const popupElement = document.getElementById('popup'); if (popupElement) { popupElement.style.display = 'none'; console.log("弹窗已关闭"); } } // 翻译弹窗内容 function translatePopup(locale) { const translations = { 'en': { 'title': "End of year offer", 'text': "Get <strong>500€ off</strong> on online bootcamps starting in 2023", 'button': "Discover Online Bootcamps" }, 'fr': { 'title': "Offre de fin d'année", 'text': "Bénéficiez d'une <strong>réduction de 500€</strong> sur les bootcamps en ligne commençant en 2023", 'button': "Découvrir les bootcamps en ligne" }, // 添加其他语言翻译 }; const localeTranslations = translations[locale] || translations['en']; const titleEl = document.querySelector('#popup .split-right h2'); const textEl = document.querySelector('#popup .split-right p'); const buttonEl = document.querySelector('#popup .split-right button'); if (titleEl) titleEl.innerHTML = localeTranslations.title; if (textEl) textEl.innerHTML = localeTranslations.text; if (buttonEl) buttonEl.textContent = localeTranslations.button; } // 初始化弹窗 function initPopup() { // 会话内已触发过,直接返回 if (hasPopupBeenTriggered()) { console.log("弹窗已在当前会话中显示过,取消初始化"); return; } const userLocale = "{{DL - locale}}"; translatePopup(userLocale); const popupElement = document.getElementById('popup'); if (!popupElement) return; // 标记弹窗已触发,避免后续触发条件再执行 markPopupAsTriggered(); // 显示弹窗 popupElement.style.display = 'block'; console.log("弹窗已显示"); // 绑定关闭按钮事件(仅绑定一次) const closeButton = document.querySelector(".close-btn"); if (closeButton && !closeButton.dataset.listenerAdded) { closeButton.addEventListener("click", closePopup); closeButton.dataset.listenerAdded = "true"; } } // 执行初始化 initPopup();
HTML代码
<div id="popup" class="popup"> <div class="popup-content"> <span class="close-btn">×</span> <div class="split-left"> <img src="#" alt="Popup image"> </div> <div class="split-right"> <h2>End of year offer</h2> <p>Get <strong>500€ off</strong> on online bootcamps starting in 2023</p> <a href="#"><button class="cta-popup">Discover Online Bootcamps</button></a> </div> </div> </div>
CSS代码
.cta-popup{ border: 0; color: white; background-color: #670BFF; text-decoration: none; padding: 0.88rem 1.4rem; border-radius: 0.5rem; font-weight: 700; cursor: pointer; } .cta-popup:hover{ background-color: #5809d9; } .split-left{ width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; } .split-left > img{ object-fit: cover; width: 100%; height: 100%; } .split-right{ display: grid; align-content: center; width: 100%; height: 100%; padding: 2rem; grid-gap: 1rem; } .popup { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.3); z-index: 99999; /* 默认隐藏弹窗 */ display: none; } .popup-content { position: absolute; display: flex; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fff; box-shadow: 0 4px 8px rgba(0,0,0,0.1); width: 500px; height: 500px; border-radius: 1rem; overflow: hidden; } .close-btn { position: absolute; right: 10px; top: 5px; font-size: 24px; cursor: pointer; z-index: 100000; }
GTM配置注意事项
- 保留原有触发条件:继续使用30秒
timer_elapsed事件触发和滚动50%触发两个触发器 - 验证数据层变量:确保
{{DL - locale}}为GTM中正确配置的“数据层变量”,变量名与dataLayer中存储locale的键完全一致 - 标签配置:将修改后的脚本设置为GTM的“自定义HTML”标签,触发条件绑定两个触发器
- 避免重复注入:无需额外调整触发优先级,核心逻辑已通过
sessionStorage确保会话内仅执行一次初始化
内容的提问来源于stack exchange,提问作者Édouard Bernard
相关产品推荐
相关产品推荐

