FullCalendar中Mutation Observer无法检测DOM元素删除的问题
嘿,我仔细看了你的代码和问题描述,核心问题其实出在Mutation Observer的判断逻辑写错了,另外还有几个小细节需要调整,咱们一步步来解决:
问题1:Mutation Observer的判断条件完全错误
你代码里写了typeof e[0].removedNodes === 'array',但实际上removedNodes是NodeList对象(不是标准JavaScript数组),所以这个条件永远不会为真,直接导致后面检测元素删除的逻辑根本跑不起来。
而且直接判断e.removedNodes[0] === elem也不靠谱——被删除的节点不一定是removedNodes里的第一个,这个判断太局限了。
问题2:FullCalendar关闭popover的额外场景
当用户点击外部区域或按ESC关闭popover时,FullCalendar的执行流程和点击关闭按钮略有不同,但只要把Observer的逻辑修对,就能覆盖所有删除场景。
修复后的完整方案
1. 彻底修正observeDeletion函数
把判断逻辑改成正确的NodeList检测方式,遍历所有被删除的节点来匹配目标元素:
function observeDeletion(elem){ var target = elem.parentNode; console.log('observing target:', target); const calPopupObserver = new MutationObserver(function (mutations) { mutations.forEach(mutation => { // 把NodeList转成数组,遍历检查是否包含目标elem Array.from(mutation.removedNodes).forEach(node => { if (node === elem) { console.log('Fixing Links - 检测到popover被删除!'); fixLinksOnCalendar(true); calPopupObserver.disconnect(); // 完成后断开监听,避免重复触发 } }); }); }); // 简化监听配置:只需要监听子节点变化,不需要subtree calPopupObserver.observe(target, { childList: true }); };
2. 可选:用FullCalendar原生事件更可靠(推荐)
其实FullCalendar V6本身提供了和popover相关的事件,比如popoverHidden,直接监听这个官方事件会比Mutation Observer更稳定,不用依赖DOM变化的监听:
// 假设你的FullCalendar实例是calendar(初始化时定义的变量) calendar.on('popoverHidden', function() { fixLinksOnCalendar(true); });
如果不想改动FullCalendar的初始化代码,只修正上面的Observer逻辑也足够解决问题。
3. 优化fixLinksOnCalendar的重复代码
你里面重复了三次几乎一样的$.each,可以合并成一次,让代码更简洁:
function fixLinksOnCalendar(repeat){ setTimeout(function(){ var calTextColor = settings.dark_ui == 'no' ? settings.colors[5]:settings.colors[4]; // 合并所有需要修改的选择器,一次遍历处理 $('.fc-more-link, a.fc-more-link, a.fc-daygrid-more-link').each(function(){ // 通用样式先设置 $(this).css({marginTop: '-10px', color: calTextColor, fontWeight: 600}); // 移动端特殊样式 if ($(window).width() < 521) { const newText = '+'+parseInt($(this).text(), 10); $(this).text(newText).css({ color: 'white', backgroundColor: settings.colors[5], padding: '3px 6px', borderRadius: '10px', marginLeft: '12px' }); } }); if (repeat) fixLinksOnCalendar(false); },300); }
测试验证
修改完observeDeletion后,再测试点击外部区域或按ESC关闭popover,你应该能在控制台看到Fixing Links - 检测到popover被删除!的日志,同时fixLinksOnCalendar会被正确调用。
备注:内容来源于stack exchange,提问作者Jason Overhulser

