首页 > 解决方案 > 网页上每个设置事件的回调函数

问题描述

例如,我有一个动画,我用 setInterval 播放它。当我之前在网页上设置的事件发生时,我希望触发一个回调函数来调用 clearInterval。好奇是否有任何方法可以为网页中存在的所有事件设置这样的回调函数。因为否则我将不得不检查我之前设置的每个事件。以代码的形式,我对类似的东西感兴趣:

const i = setInterval(function() {
    //do something
}, 50);

AdditionalCallbackForEveryEventSet(function() {
    clearInterval(i);
});

标签: javascript

解决方案


我也有类似的经历,但想在从 DOM 中删除自定义组件时清理所有侦听器(因此,我使用.call(). 这对您来说可能有点过于复杂,但我想指出的是,您需要构建一个您需要使用的功能,而不是setInterval/addEventListener直接设置间隔/侦听器。

一些例子

添加监听器
FXListenerBehavior.setListener.call(window, 'aKeyToDiffentiate', functionName);

移除监听器
FXListenerBehavior.clearListener.call(window, 'aKeyToDiffentiate', functionName);

添加间隔
const TIME_IN_MILLIS = 2000;
FXListenerBehavior.setInterval.call(window, 'aKeyToDiffentiate', functionName, TIME_IN_MILLIS);

删除所有间隔和侦听器
FXListenerBehavior.clearAllIntervals.call(window);

调试时打印所有侦听器和间隔
很好。
FXListenerBehavior.printAll.call(window);

删除所有侦听器和间隔
FXListenerBehavior.clearAll.call(window);

FXListenerBehavior = {

  /* === SET AND UPDATE === */

  /**
   * @description sets a listener
   * @param {String} name any descriptive name
   * @param {function} method the function to be run with the listener
   * @param {setOnElement} Boolean if the listener should be set on the element or default to window
   * @return {Boolean} true if set, false if listener already exist
   */
  setListener: function(name, method, setOnElement) {
    if (FXListenerBehavior._alreadyExist.call(this, name)) {
      var elementName = FXListenerBehavior._getElementName.call(this);

      console.warn(elementName + '\"' + name + '\" already exist. Use updateListener() if you\'re unsure if the listener exists');

      return false;
    }

    return FXListenerBehavior._setListener.call(this, name, method, setOnElement);
  },

  /**
   * @description sets an interval
   * @param {String} name any descriptive name
   * @param {function} method the method to be repeated
   * @param {Integer} time repeats method after this many milliseconds
   * @return {Boolean} true if set, false if listener already exist
   */
  setInterval: function(name, method, time) {
    if (FXListenerBehavior._alreadyExist.call(this, name)) {
      var elementName = FXListenerBehavior._getElementName.call(this);

      console.warn(elementName + '\"' + name + '\" already exist. Use updateInterval() if you\'re unsure if the interval exists');

      return false;
    }

    return FXListenerBehavior._setInterval.call(this, name, method, time);
  },

  /**
   * @description replaces a listener or interval, or creates one if it doesn't exist
   * @param {String} name any descriptive name
   * @param {function} method the method to be run
   * @param {Integer} time repeats method after this many milliseconds (only for intervals)
   * @return {Boolean} always true
   */
  update: function(name, method, time) {
    if (time > 0) {
      return FXListenerBehavior.updateInterval.call(this, name, method, time);
    } else {
      var setOnElement = time;
      return FXListenerBehavior.updateListener.call(this, name, method, setOnElement);
    }
  },

  updateListener: function(name, method, setOnElement) {
    FXListenerBehavior.clearListener.call(this, name);
    return FXListenerBehavior._setListener.call(this, name, method, setOnElement);
  },

  updateInterval: function(name, method, time) {
    FXListenerBehavior.clearInterval.call(this, name);
    return FXListenerBehavior._setInterval.call(this, name, method, time);
  },

  _setListener: function(name, method, setOnElement) {
    if (name == undefined || method == undefined) {
      traceDebug('name or method is undefined', name, method)
      return
    }

    this._listenersAndIntervals[name] = method;

    if (setOnElement) {
      this.addEventListener(name, method, {
        'passive': true
      });
    } else {
      window.addEventListener(name, method, {
        'passive': true
      });
    }

    return true;
  },

  _setInterval: function(name, method, time) {
    if (name == undefined || method == undefined) {
      traceDebug('name or method is undefined', name, method)
      return
    }

    var intervalId = setInterval(method, time);
    this._listenersAndIntervals[name] = intervalId;
    return true;
  },

  _alreadyExist: function(name) {
    if (typeof this._listenersAndIntervals === 'undefined') {
      this._listenersAndIntervals = {};
    }

    if (this._listenersAndIntervals[name]) {
      return true;
    }

    return false;
  },


  /* === GET AND PRINT === */


  getAll: function() {
    return Object.keys(this._listenersAndIntervals);
  },

  printAll: function() {
    if (this._listenersAndIntervals) {
      var isPolymer2Element = this.is == 'function';
      let elementName = (isPolymer2Element) ? this.is() : this.is;

      console.info("All listeners and intervals for " + elementName + ":\n" + JSON.stringify(Object.keys(this._listenersAndIntervals)));
    }
  },


  /* === CLEAR === */


  /**
   * @description clears a listener
   * @param {String} name any descriptive name, previously set with setListener
   */
  clearListener: function(name) {
    if (FXListenerBehavior._alreadyExist.call(this, name)) {
      window.removeEventListener(name, this._listenersAndIntervals[name])
      delete this._listenersAndIntervals[name];
    }
  },

  /**
   * @description clears an interval
   * @param {String} name any descriptive name, previously set with setInterval
   */
  clearInterval: function(name) {
    if (FXListenerBehavior._alreadyExist.call(this, name)) {
      clearInterval(this._listenersAndIntervals[name]);
      delete this._listenersAndIntervals[name];
    }
  },

  clearAllListeners: function() {
    FXListenerBehavior._clear.call(this, 'listener');
  },

  clearAllIntervals: function() {
    FXListenerBehavior._clear.call(this, 'interval');
  },

  clearAll: function(print) {
    if (print) {
      FXListenerBehavior.printAll.call(this)
    }

    FXListenerBehavior._clear.call(this);

    if (print) {
      FXListenerBehavior.printAll.call(this)
    }
  },

  _clear: function(listenerOrInterval) {
    if (typeof this._listenersAndIntervals === 'object') {

      var keys = Object.keys(this._listenersAndIntervals);

      for (var i = keys.length - 1; i >= 0; i--) {
        if (typeof this._listenersAndIntervals[keys[i]] === 'function' && listenerOrInterval !== 'interval') {
          FXListenerBehavior.clearListener.call(this, keys[i]);
        } else if (typeof this._listenersAndIntervals[keys[i]] === 'number' && listenerOrInterval !== 'listener') {
          FXListenerBehavior.clearInterval.call(this, keys[i]);
        } else {
          var elementName = FXListenerBehavior._getElementName.call(this);

          console.warn(elementName + keys[i] + ' is not a ' + (listenerOrInterval || 'listener'));
        }
      }

    }
  },

  _getElementName: function() {
    var elementName = this.is ||  this.tagName || this.nodeName;

    if (!elementName) {
      traceDebug('FXListenerBehavior lacks element information');
    }

    return (this) ? elementName + ': ' : '';
  }
}


推荐阅读