DRY复用MutationObserver:如何存储多元素属性变更用于条件判断
之前方案失效的核心原因
- MutationObserver的回调是异步执行的,触发时机远晚于函数调用的同步流程,无法在函数调用的同步阶段拿到mutation值
- JavaScript的基础类型传参是按值传递,在函数内部给形参
y赋值,不会修改外层声明的变量,最终读取时自然拿到undefined - 多个元素共用一个全局变量存mutation值,会出现不同元素的变更数据互相覆盖的问题,无法满足每个card专属规则的需求
正确实现思路
- 放弃同步读取异步回调结果的思路,改为给每个被跟踪的元素绑定专属的变更处理回调,在变更触发时直接执行对应规则
- 用和DOM元素绑定的独立存储结构,为每个元素单独维护观察者实例、历史变更记录,从根本上避免不同元素的数据串扰
- 增加重复绑定的去重逻辑,避免同一元素多次绑定观察者导致的重复触发问题
修正后的完整实现
// 用WeakMap存储每个元素的跟踪数据,元素销毁时自动释放内存,无泄漏风险 const elementTrackMap = new WeakMap(); /** * 跟踪指定元素的属性变更 * @param {HTMLElement} current 被跟踪的DOM元素 * @param {Function} changeHandler 属性变更触发时的专属处理函数 */ function track_attr_changes(current, changeHandler) { // 若该元素已绑定过观察者,先断开旧监听,避免重复触发 if (elementTrackMap.has(current)) { const oldObserver = elementTrackMap.get(current).observer; oldObserver.disconnect(); } const observer = new MutationObserver((mutations) => { const trackData = elementTrackMap.get(current); mutations.forEach((mutation) => { // 将变更存入对应元素的历史记录,需要时可直接读取 trackData.mutationHistory.push(mutation); // 执行该元素专属的变更处理逻辑 if (typeof changeHandler === 'function') { changeHandler(mutation, current); } }); }); const config = { attributes: true, attributeOldValue: true, subtree: true }; // 初始化该元素的跟踪数据 elementTrackMap.set(current, { observer, mutationHistory: [] }); observer.observe(current, config); } // 原有业务逻辑 var cards = document.querySelectorAll('.card'); cards.forEach(element => { element.addEventListener('click', () => { element.classList.toggle('active'); }); // 为每个card传入专属的变更校验规则,逻辑完全隔离 track_attr_changes(element, (mutation, targetEl) => { console.log(`检测到卡片属性变更:`, mutation); // 示例规则:当class属性变更时,判断激活状态做对应处理 if (mutation.attributeName === 'class') { if (targetEl.classList.contains('active')) { console.log('当前卡片已激活,可执行对应专属规则'); } else { console.log('当前卡片已取消激活'); } } }); });
方案说明
- 不需要靠外层临时变量存mutation值,异步触发回调时直接传入最新的变更数据和对应的元素对象,解决了之前赋值读不到的问题
- 每个元素的变更记录独立存储,随时可通过
elementTrackMap.get(目标元素).mutationHistory读取该元素的所有历史变更 - 所有自定义规则都通过入参传入,同一个
track_attr_changes方法可以复用到任意多元素的场景,不需要为不同元素改核心函数逻辑
内容的提问来源于stack exchange,提问作者001
相关产品推荐
相关产品推荐

