You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何监听元素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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 08:57:20