修复ASP日历弹窗切换月份后事件失效:如何重新绑定JS事件?
经典ASP日历控件CSP适配后月份切换事件失效问题
我正在修复一个经典ASP程序以适配Content Security Policy(CSP)。该程序中的日历弹窗主要由JavaScript构建,需要实现月份前后切换的点击事件,以及点击日期时设置文本框的功能。
控件主体代码:
<body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0" > <div class="calendardiv" id="calendar2"></div> </body>
页面引入的JavaScript负责拼接日历元素:
var output = '<table border="0" cellspacing="0" cellpadding="0" class="calendar_table">'; output += '<tr class="header color_1_3">'; output += '<td><a ID="BACK" class="mod_head_link" href="#" ><<</a></td>'; output += '<td colspan="5" class="mod_head_text">' + strMonth.toUpperCase() + ", " + nYear + '</td>'; output += '<td><a ID="FORWARD" class="mod_head_link" href="#" >>></a></td>'; output += '</tr>'; output += '</table>'; return output;
拼接后将内容设置为calendardiv.innerHTML。控件首次弹出时执行:
document.addEventListener("DOMContentLoaded", function () { loadCalendar(); set_event_handlers(); }, false);
set_event_handlers函数定义:
function set_event_handlers() { var back_obj = document.getElementById("BACK"); if (back_obj == null) { } else { back_obj.addEventListener("click", function () { back("mo"); }, false); } var forward_obj = document.getElementById("FORWARD"); if (forward_obj == null) { } else { forward_obj.addEventListener("click", function () { forward("mo"); // 注:原代码存在笔误,此处应为forward而非forward_obj }, false); } for (i = 1; i <= 31; i++) { vDay_obj = document.getElementById(i); if (vDay_obj == null) { vDay_obj = document.getElementById("today"); } if (vDay_obj == null) { alert('null'); } else { vDay_obj.addEventListener("click", function () { showDate(this); }, false); vDay_obj.addEventListener("mouseout", function () { restore(this); }, false); vDay_obj.addEventListener("mouseover", function () { hilite(this); }, false); } } }
切换月份后,事件不再触发(切换时会重新执行loadCalendar更新innerHTML)。需要解决:如何在calendardiv更新新元素后触发set_event_handlers?应使用什么事件,代码应设置在何处?
解决方案
方案1:事件委托(推荐,适配CSP且更高效)
事件委托利用事件冒泡机制,将事件绑定在父容器calendar2上,无需每次更新DOM后重新绑定事件,完全符合CSP对禁止内联事件的要求。
修改代码如下:
document.addEventListener("DOMContentLoaded", function () { loadCalendar(); // 绑定父容器的事件委托 const calendarContainer = document.getElementById("calendar2"); // 处理前后切换点击 calendarContainer.addEventListener("click", function(e) { const target = e.target; e.preventDefault(); // 阻止a标签默认跳转#的行为 if (target.id === "BACK") { back("mo"); } else if (target.id === "FORWARD") { forward("mo"); } else if (target.tagName === "TD" && (target.id >=1 && target.id <=31 || target.id === "today")) { // 处理日期点击 showDate(target); } }); // 处理日期的鼠标悬停效果 calendarContainer.addEventListener("mouseover", function(e) { const target = e.target; if (target.tagName === "TD" && (target.id >=1 && target.id <=31 || target.id === "today")) { hilite(target); } }); calendarContainer.addEventListener("mouseout", function(e) { const target = e.target; if (target.tagName === "TD" && (target.id >=1 && target.id <=31 || target.id === "today")) { restore(target); } }); }, false);
方案2:更新DOM后手动调用事件绑定函数
如果保留原有事件绑定逻辑,只需在每次通过innerHTML更新calendar2内容后,立即调用set_event_handlers。
找到执行innerHTML赋值的代码位置(一般在loadCalendar函数内),添加调用:
function loadCalendar() { // 原有拼接日历HTML的逻辑... const calendarDiv = document.getElementById("calendar2"); calendarDiv.innerHTML = output; // 更新DOM后立即重新绑定事件 set_event_handlers(); }
这样每次切换月份调用loadCalendar时,新生成的DOM元素都会被绑定事件。
失效原因说明
每次切换月份时,innerHTML会替换calendar2内的所有DOM节点,原来绑定了事件的旧元素被移除,新生成的元素未绑定任何事件,因此点击操作无响应。
内容的提问来源于stack exchange,提问作者MGSeggerman
相关产品推荐
相关产品推荐

