JS 事件禁用器:无法阻止本机事件侦听器执行



我正在实现一个JS事件禁用类,以禁用某个dom元素及其所有子元素的所有本机和可编程事件侦听器。

到目前为止,我已经能够禁用所有的JQuery事件和默认的浏览器事件,但不能像

那样设置事件侦听器。
document.getElementById('cin').addEventListener("click", function(){
        alert('I should not alert when disabled');
});

所以点击元素('native element')不应该发出警告,但是它发出了。如何在我的"无"函数中阻止这种情况的发生。如果有甚至不需要调用另一个函数,而只是禁用所有事件,那么这也会很好,但需要能够重新启用所有再次。

同时,我可以向您保证nothing()函数会首先执行。

var tellme = function(who) {
  //console.info('Event by: '+who+' @'+Date.now());   
  alert('Event by: ' + who + ' @' + Date.now());
}
$(window).load(function() {
  /* SOME FUNCTION TO ENSURE OUR FUNCTIONS ARE THE FIRST TO BE CALLED */
  $.fn.bindFirst = function(name, fn) {
    this.on(name, fn);
    this.each(function() {
      var handlers = $._data(this, 'events');
      for (var key in handlers) {
        if (handlers.hasOwnProperty(key)) {
          var listeners = handlers[key];
          if (listeners.length > 1) {
            var lastEvent = listeners.pop();
            listeners.splice(0, 0, lastEvent);
            if (listeners[1].handler.name === lastEvent.handler.name)
              listeners.splice(1, 1);
          }
        }
      }
    });
  };
  function shouldbenothing() {
      tellme('native catcher');
      nothing();
    }
    /* THE DO NOTHING FUNCTION, NEEDS SOMETHING MORE, DOESN'T CANCEL ALL*/
  function nothing() {
    event.cancel = true;
    event.preventDefault();
    event.stopPropagation();
    event.stopImmediatePropagation();
    //Needed for Jquery
    throw new Error("NOT AN ERROR: Just forcefully stopping further events @" /*+Date.now()*/ ); //Add the Date.now to see that this code does run before the native function.
    return false;
  }
  /* THIS WILL ONLY RETURN NON-NATIVE EVENTS, ONLY PROGRAMMED EVENTS*/
  function getAllActiveEvents(element) {
    var result = [];
    var handlers = $._data(element, 'events');
    for (var key in handlers) {
      if (handlers.hasOwnProperty(key)) {
        result.push(key);
      }
    }
    return result.join(' ');
  }
  function getAllEvents(element) {
    var result = [];
    for (var key in element) {
      if (key.indexOf('on') === 0) {
        result.push(key.slice(2));
      }
    }
    return result.join(' ');
  }
  /*SOME PROGRAMMED EVENTS, BESIDES THE NATIVE ONES*/
  $('input').on('keyup', function() {
    $('#text').html(this.value);
  });
  $('p').on('click', function() {
    $('#text').html(this.innerHTML);
    tellme('jquery');
  });
  document.getElementById('jsE').addEventListener("click", function() {
    tellme('p:js');
  });
  document.getElementById('cin').addEventListener("click", function() {
    tellme('input:js');
  });
  /* THE ACTUAL DISABLER CODE */
  /*TOGGLE TO ACTIVE OR DISABLE EVENTS FROM TAKING PLACE NATIVE AND EXTRA*/
  var isOn = false;
  $('button').on('click', function() {
    if (isOn)
      $("#obj *").each(function() {
        $(this).off(getAllEvents($(this)[0]), "", nothing);
        $("#obj").css('pointerEvents','');
      });
    else {
      $("#obj *").each(function() {
        var elem = $(this)[0];
        var events1 = getAllActiveEvents(elem); //Only programmed listeners
        var events2 = getAllEvents(elem); //Native + other listeners
        $(this).bindFirst(events2, nothing);
      });
      $("#obj").css('pointerEvents','none');
    }
    isOn = !isOn;
    this.innerHTML = isOn;
  });
});
p {
  cursor: pointer;  
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<style>p {pointer:hand;}</style>
<div id="obj">
  <p>jquery event</p>
  <p id="jsE">js event</p>
  <p onclick="tellme('native');">native event</p>
  <input id='cin' type="text" />
  <p id="text">3</p>
</div>
<p>not catched</p>
<input type="text">
<button>toggle</button>

可能有一个非常简单的,非js的,纯css的解决方案…这样的:

.whatever {
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    pointer-events:none;
}

…只需将whatever -class添加到任何您想要完全禁用用户交互的元素中。

所以我很快就找到了一个解决方案。通过使用css代码,我可以禁用所有相关的鼠标事件。然而,如果你想通过JS触发事件,这并不能阻止本地事件,但至少它可以从用户的角度阻止它。

实际上我也更喜欢css方法,因为它允许我仍然交互和触发事件,例如当我想向用户显示一些东西而不让用户干扰时。

css代码:
//To Disable    
$("#obj").css('pointerEvents','none');
//To Enable
$("#obj").css('pointerEvents','');

对于任何寻找完整工作代码的人:这里是。确保你添加了css。

/* Event Disabler, disables all events */
/* How to use:
*    Toggle Events: toggleEvents(selector);
*    Disable all Events: toggleEvents('body',true);
*    Enable all Events: toggleEvents('body',false);
*/
var toggleEvents = null;
$(window).load(function(){
    /* SOME FUNCTION TO ENSURE OUR FUNCTIONS ARE THE FIRST TO BE CALLED */
    $.fn.bindFirst = function(name, fn) {
        this.on(name, fn);
        this.each(function() {
        var handlers = $._data(this, 'events');
        for (var key in handlers) {
            if (handlers.hasOwnProperty(key)) {
                var listners = handlers[key];
                if (listners.length > 1) {				
                    var lastEvent = listners.pop();
                    listners.splice(0, 0, lastEvent);          
                    //Removes duplicate eventListners
                    if (listners[1].handler.name === lastEvent.handler.name)
                        listners.splice(1, 1);
                }
            }
        }
        });
    };
    /* THE DO NOTHING FUNTION CANCELS ALL EVENTS, EVEN BY TRIGGERED*/
    function nothing() {
        event.cancel = true;
        event.preventDefault();         
        event.stopPropagation();
        event.stopImmediatePropagation();
        event.bubbles = false;    
        if(window.event){
           window.event.cancelBubble=true;
        }
        //throw new Error("NOT AN ERROR: Forcefully stopping further events");
        return false;
    }
    function getAllActiveEvents(element) {
        var result = [];
        var handlers = $._data(element, 'events');
        for (var key in handlers) {
            if (handlers.hasOwnProperty(key)) {
                result.push(key);
            }
        }
        return result.join(' ');
    }
    function getAllEvents(element) {
        var result = [];
        for (var key in element) {
            if (key.indexOf('on') === 0) {
                result.push(key.slice(2));
            }
        }
        return result.join(' ');
    }
    
    var enabled = false;
    toggleEvents = function(selector,flag) {
        enabled = flag === undefined ? !enabled : flag;
        if (enabled) {
            $(selector+" *").each(function(){	
                //Only programmed and attached listners
                var events1 = getAllActiveEvents($(this)[0]); 
                //All Native events attached or not
                var events2 = getAllEvents($(this)[0]); 
                $(this).bindFirst(events2, nothing );                
            });  
            //Disabled most user pointer events
            $(selector).addClass('eventsDisabled');    
        } else {
            $(selector+" *").each(function() {
                $(this).off(getAllEvents($(this)[0]), "", nothing );
            });
            $(selector).removeClass('eventsDisabled');
        }
    };
});
.eventsDisabled {
    -webkit-user-select:none !important;
    -moz-user-select:none !important;
    -ms-user-select:none !important;
    user-select:none !important;
    pointer-events:none !important;    
}

最新更新