如何监听元素data-color属性变更并获取其变化前的旧值
问题需求
在代码标注/* YOUR CODE HERE */的区域编写逻辑,每次id为#cro-headline的元素的data-color属性变更时,在控制台输出该属性的当前值与变更前旧值,日志格式要求如下:
console.log('Current color: ' + currentColor + ' | Previous Color: ' + previousColor);
现有实现问题
当前尝试的方案存在逻辑错误:误将目标元素的上一个相邻兄弟节点(previousElementSibling)的data-color值当作属性旧值,完全无法获取data-color属性本身的历史值,错误代码如下:
var oldFunction = window.changeHeadlineColor; window.changeHeadlineColor = function(croHeadline) { oldFunction(croHeadline); var currentElement = document.querySelector('#cro-headline'); var currentColor = currentElement.dataset.color; var previousElement = currentElement.previousElementSibling; var previousColor = previousElement.dataset.color; console.log('Current color: ' + currentColor + ' | Previous Color: ' + previousColor); }
测试环境代码
以下是题目提供的完整可运行HTML示例:
<!DOCTYPE html> <html lang="en"> <head> <style> [data-color="red"] { color: red; } [data-color="blue"] { color: blue; } [data-color="green"] { color: green; } [data-color="orange"] { color: orange; } [data-color="purple"] { color: purple; } </style> <script> window.myHandler = function () { console.log('Click!'); }; window.getRandomNumber = function (max) { return Math.floor(Math.random() * max) } var colors = ['red', 'blue', 'green', 'orange', 'purple']; window.changeHeadlineColor = function (croHeadline) { var random = getRandomNumber(5000); var randomString = random.toString(); setTimeout(() => { var colorKey = (randomString.length < 4) ? 0 : parseInt(randomString.charAt(0)); croHeadline.setAttribute('data-color', colors[colorKey]); changeHeadlineColor(croHeadline); }, random); }; </script> <script> //////////////////// /* YOUR CODE HERE */ //////////////////// </script> </head> <body> <div id="myDiv">OMG Click me!</div> <script> document.querySelector('#myDiv').addEventListener('click', myHandler); setTimeout(() => { myDiv.insertAdjacentHTML('beforebegin', '<h1 id="cro-headline" data-color="red">Cro Metrics</h1>'); var croHeadline = document.querySelector('#cro-headline'); changeHeadlineColor(croHeadline); }, getRandomNumber(5000)); </script> </body> </html>
实现代码
直接将以下代码填入/* YOUR CODE HERE */标注区域即可生效:
// 轮询等待目标元素挂载到DOM const bindColorListener = () => { const headlineEl = document.querySelector('#cro-headline'); if (!headlineEl) { setTimeout(bindColorListener, 100); return; } // 用闭包变量存储上一次的颜色值,初始为元素默认的data-color值 let previousColor = headlineEl.dataset.color; // 初始化属性变更监听器 const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.attributeName === 'data-color') { const currentColor = headlineEl.dataset.color; console.log('Current color: ' + currentColor + ' | Previous Color: ' + previousColor); // 打印完成后更新旧值为当前值,供下一次变更使用 previousColor = currentColor; } }) }) // 开始监听元素的data-color属性变更 observer.observe(headlineEl, { attributes: true, attributeFilter: ['data-color'] }) } bindColorListener();
实现说明
- 由于
#cro-headline是延迟插入DOM的,所以加了轻量轮询判断元素是否存在,避免初始化监听时找不到目标 - 用闭包变量持久化存储上一次的颜色值,每次属性变更触发回调时,先读取当前值和存储的旧值按要求打印,再将旧值更新为当前值,保证取值完全准确
- 采用原生
MutationObserverAPI实现DOM属性监听,不侵入修改原有业务方法,无论通过什么渠道修改data-color属性都能被捕获,兼容性和鲁棒性更好
内容的提问来源于stack exchange,提问作者Marc
相关产品推荐
相关产品推荐

