【问题标题】:Event trigger on a class change类更改的事件触发器
【发布时间】:2012-05-23 15:08:50
【问题描述】:

我希望在包含 trigger 类的 div 标签发生更改时触发我的事件。

我不知道如何让它监听班级的添加事件。

<div id="test">test</div>

<script type="text/javascript">
    document.getElementById.setAttribute("class", "trigger");

    function workOnClassAdd() {
       alert("I'm triggered");
    }
</script>

【问题讨论】:

  • 您确定知道该类将使用.setAttribute() 进行更新,还是您用更随意的术语谈论(即,即使用户通过 Firebug 更改了类,您也希望触发事件处理程序)?

标签: javascript


【解决方案1】:

未来已来,您可以使用MutationObserver 接口来观察特定类的变化。

let targetNode = document.getElementById('test')

function workOnClassAdd() {
    alert("I'm triggered when the class is added")
}

function workOnClassRemoval() {
    alert("I'm triggered when the class is removed")
}

// watch for a specific class change
let classWatcher = new ClassWatcher(targetNode, 'trigger', workOnClassAdd, workOnClassRemoval)

// tests:
targetNode.classList.add('trigger') // triggers workOnClassAdd callback
targetNode.classList.add('trigger') // won't trigger (class is already exist)
targetNode.classList.add('another-class') // won't trigger (class is not watched)
targetNode.classList.remove('trigger') // triggers workOnClassRemoval callback
targetNode.classList.remove('trigger') // won't trigger (class was already removed)
targetNode.setAttribute('disabled', true) // won't trigger (the class is unchanged)

我用一个简单的类包裹了 MutationObserver

class ClassWatcher {

    constructor(targetNode, classToWatch, classAddedCallback, classRemovedCallback) {
        this.targetNode = targetNode
        this.classToWatch = classToWatch
        this.classAddedCallback = classAddedCallback
        this.classRemovedCallback = classRemovedCallback
        this.observer = null
        this.lastClassState = targetNode.classList.contains(this.classToWatch)

        this.init()
    }

    init() {
        this.observer = new MutationObserver(this.mutationCallback)
        this.observe()
    }

    observe() {
        this.observer.observe(this.targetNode, { attributes: true })
    }

    disconnect() {
        this.observer.disconnect()
    }

    mutationCallback = mutationsList => {
        for(let mutation of mutationsList) {
            if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                let currentClassState = mutation.target.classList.contains(this.classToWatch)
                if(this.lastClassState !== currentClassState) {
                    this.lastClassState = currentClassState
                    if(currentClassState) {
                        this.classAddedCallback()
                    }
                    else {
                        this.classRemovedCallback()
                    }
                }
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    好吧,有mutation events,但它们已被弃用,未来还会有 Mutation Observers,但很长一段时间内不会完全支持它们。那么在此期间你能做些什么呢?

    您可以使用计时器来检查元素。

    function addClassNameListener(elemId, callback) {
        var elem = document.getElementById(elemId);
        var lastClassName = elem.className;
        window.setInterval( function() {   
           var className = elem.className;
            if (className !== lastClassName) {
                callback();   
                lastClassName = className;
            }
        },10);
    }
    

    运行示例:jsFiddle

    【讨论】:

    【解决方案3】:

    这是一个关于如何触发类属性更改回调的简单基本示例
    MutationObserver API

    const attrObserver = new MutationObserver((mutations) => {
      mutations.forEach(mu => {
        if (mu.type !== "attributes" && mu.attributeName !== "class") return;
        console.log("class was modified!");
      });
    });
    
    const ELS_test = document.querySelectorAll(".test");
    ELS_test.forEach(el => attrObserver.observe(el, {attributes: true}));
    
    
    // Example of Buttons toggling several .test classNames
    document.querySelectorAll(".btn").forEach(btn => {
      btn.addEventListener("click", () => ELS_test.forEach(el => el.classList.toggle(btn.dataset.class)));
    });
    .blue {background: blue;}
    .gold {color: gold;}
    <div class="test">TEST DIV</div>
    <button class="btn" data-class="blue">BACKGROUND</button>
    <button class="btn" data-class="gold">COLOR</button>

    【讨论】:

      【解决方案4】:

      我需要一个项目的类更新监听器,所以我做了这个。我最终没有使用它,所以它没有经过全面测试,但在支持 Element.classList DOMTokenList 的浏览器上应该没问题。

      奖励:允许“链接” 4 种支持的方法,例如 el.classList.remove(“inactive”).remove(“disabled”).add(“active”)

      function ClassListListener( el ) {
        const ecl = el.classList;
        ['add','remove','toggle','replace'].forEach(prop=>{
          el.classList['_'+prop] = ecl[prop]
          el.classList[prop] = function() {
            const args = Array.from(arguments)
            this['_'+prop].apply(this, args)
            el.dispatchEvent(new CustomEvent(
              'classlistupdate',
              { detail: { method: prop, args } }
            ))
            return this
          }
        })
        return el
      }
      

      用途:

      
      const el = document.body
      
      ClassListListener(el).addEventListener('classlistupdate', e => {
          const args = e.detail.args.join(', ')
          console.log('el.classList.'+e.detail.method+'('+args+')')
      }, false)
      
      el.classList
        .add('test')
        .replace('test', 'tested')
      

      【讨论】:

      • 您好,欢迎来到stackoverflow,您可以使用更具描述性的变量名吗?
      • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
      【解决方案5】:

      可以使用这个onClassChange 函数来观察classList 的元素何时发生变化

      function onClassChange(element, callback) {
        const observer = new MutationObserver((mutations) => {
          mutations.forEach((mutation) => {
            if (
              mutation.type === 'attributes' &&
              mutation.attributeName === 'class'
            ) {
              callback(mutation.target);
            }
          });
        });
        observer.observe(element, { attributes: true });
        return observer.disconnect;
      }
      
      var itemToWatch = document.querySelector('#item-to-watch');
      onClassChange(itemToWatch, (node) => {
        node.classList.contains('active')
          ? alert('class added')
          : alert('class removed');
        node.textContent = 'Item to watch. classList: ' + node.className;
      });
      
      function addClass() {
        itemToWatch.classList.add('active');
      }
      
      function removeClass() {
        itemToWatch.classList.remove('active');
      }
      <div id="item-to-watch">Item to watch</div>
      <button onclick="addClass();">Add Class</button>
      <button onclick="removeClass();">Remove Class</button>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-18
        • 2013-10-24
        相关资源
        最近更新 更多