后续点击事件触发错误href链接问题排查求助
外部链接离开提醒弹窗异常排查
问题现象
开发的外部链接提醒脚本,逻辑为:点击非白名单域名的外部链接时,触发「离开站点提醒」弹窗。首次点击功能正常,但后续点击其他外部链接时,弹窗虽能正常触发,但点击弹窗的「Okay」按钮后,会跳转到首次点击的链接,而非当前点击的目标链接。
提供的代码
jQuery控制代码(含Hubl注入)
$(window).on("load", function() { const popup = $('.alert-popup-container'); const domains = []; // populate whitelisted domains array - **fyi this is written in hubl** {% for item in module.domains %} domains.push("{{ item }}"); {% endfor %} function confirm (link) { popup.addClass('active'); $('.popup-cancle, .alert-popup-close').click(function(e){ e.preventDefault(); popup.removeClass('active'); return true; }); $('.popup-proceed').click(function(e){ e.preventDefault(); window.open(link, "_blank"); popup.removeClass('active'); return true; }); } $('a').on('click', function(e){ const target = $(this), href = target.attr("href"); var trigger_alert = true; // make sure url is not relative if (href.indexOf('://') !== -1) { for (var i = 0; i < domains.length; i++) { if (href.indexOf(domains[i]) != -1) { trigger_alert = false; // don't trigger the alert } } if (trigger_alert) { e.preventDefault(); confirm(target.attr("href")); } } }); });
弹窗HTML代码
<div class="alert-popup-container"> <div class="alert-popup"> <div class="alert-popup-close"></div> {{ module.alert_text }} <div class='controls'> <div class="btn1"> <a href="#" class='cta_button popup-proceed'>Okay</a> </div> <div class="btn2"> <a href="#" class='cta_button popup-cancle'>Cancel</a> </div> </div> </div> </div>
问题原因
核心问题是重复绑定点击事件:
- 每次调用
confirm()函数时,都会给弹窗的.popup-proceed、.popup-cancle等按钮绑定新的点击事件,旧的事件不会被覆盖,而是叠加在元素上。 - 第一次点击链接时,
confirm()绑定的事件闭包捕获了首次的link参数;后续点击其他链接时,新绑定的事件虽然携带了当前的link,但点击按钮时会优先执行最早绑定的事件,因此打开的始终是首次点击的链接。
修复方案
方案1:绑定前解绑旧事件
修改confirm()函数,在绑定新事件前,先解绑按钮上已存在的点击事件,避免事件叠加:
function confirm (link) { popup.addClass('active'); // 先解绑所有旧的点击事件,再绑定新事件 $('.popup-cancle, .alert-popup-close').off('click').click(function(e){ e.preventDefault(); popup.removeClass('active'); }); $('.popup-proceed').off('click').click(function(e){ e.preventDefault(); window.open(link, "_blank"); popup.removeClass('active'); }); }
方案2:事件委托(更优)
将弹窗按钮的点击事件只绑定一次到父容器,通过变量存储当前要跳转的链接,避免重复绑定问题:
$(window).on("load", function() { const popup = $('.alert-popup-container'); const domains = []; {% for item in module.domains %} domains.push("{{ item }}"); {% endfor %} // 存储当前待跳转的链接 let currentTargetLink = ''; // 仅绑定一次弹窗按钮的事件 $('.popup-cancle, .alert-popup-close').click(function(e){ e.preventDefault(); popup.removeClass('active'); currentTargetLink = ''; // 清空存储的链接 }); $('.popup-proceed').click(function(e){ e.preventDefault(); if(currentTargetLink) { window.open(currentTargetLink, "_blank"); currentTargetLink = ''; } popup.removeClass('active'); }); $('a').on('click', function(e){ const target = $(this), href = target.attr("href"); let trigger_alert = true; if (href.indexOf('://') !== -1) { for (let i = 0; i < domains.length; i++) { if (href.indexOf(domains[i]) !== -1) { trigger_alert = false; break; // 找到匹配域名后跳出循环,优化性能 } } if (trigger_alert) { e.preventDefault(); currentTargetLink = href; // 存储当前点击的链接 popup.addClass('active'); } } }); });
额外优化
在白名单域名检测的循环中,找到匹配域名后立即break,无需继续遍历,提升脚本执行效率。
内容的提问来源于stack exchange,提问作者Jillian Hoenig
相关产品推荐
相关产品推荐

