在 JavaScript 中的匿名函数上移除 EventListener

我有一个包含方法的对象。这些方法被放入匿名函数中的对象中。它看起来像这样:

var t = {};
window.document.addEventListener("keydown", function(e) {
t.scroll = function(x, y) {
window.scrollBy(x, y);
};
t.scrollTo = function(x, y) {
window.scrollTo(x, y);
};
});

(有更多的代码,但这足以显示问题)

现在我想在某些情况下停止事件侦听器。因此,我尝试做一个 RemoveEventListener,但我不知道如何做到这一点。我在其他问题中读到,不可能对匿名函数调用 RemoveEventListener,但是在这种情况下也是这种情况吗?

我在 t 中创建了一个方法在匿名函数中因此我认为这是可能的。看起来像这样:

t.disable = function() {
window.document.removeEventListener("keydown", this, false);
}

为什么我不能这么做?

还有其他(好的)方法来做这件事吗?

额外的信息; 这只能在 Safari 中工作,因此缺少 IE 支持。

148710 次浏览

我相信这就是匿名函数的意义所在,它缺少一个名称或引用它的方式。

如果我是你,我会创建一个命名的函数,或者把它放在一个变量中,这样你就有了一个对它的引用。

var t = {};
var handler = function(e) {
t.scroll = function(x, y) {
window.scrollBy(x, y);
};
t.scrollTo = function(x, y) {
window.scrollTo(x, y);
};
};
window.document.addEventListener("keydown", handler);

然后你可以通过

window.document.removeEventListener("keydown", handler);

如果位于实际函数中,则可以使用 arguments.callee 作为对函数的引用。如下所示:

button.addEventListener('click', function() {
///this will execute only once
alert('only once!');
this.removeEventListener('click', arguments.callee);
});

编辑: 如果您在严格模式("use strict";)下工作,这将无法工作

一个不那么匿名的选择

element.funky = function() {
console.log("Click!");
};
element.funky.type = "click";
element.funky.capt = false;
element.addEventListener(element.funky.type, element.funky, element.funky.capt);
// blah blah blah
element.removeEventListener(element.funky.type, element.funky, element.funky.capt);

由于收到了来自 Andy (非常正确,但是和许多例子一样,我希望展示这个想法的上下文扩展)的强烈反馈,这里有一个 没那么复杂的展示:

<script id="konami" type="text/javascript" async>
var konami = {
ptrn: "38,38,40,40,37,39,37,39,66,65",
kl: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
};
document.body.addEventListener( "keyup", function knm ( evt ) {
konami.kl = konami.kl.slice( -9 );
konami.kl.push( evt.keyCode );
if ( konami.ptrn === konami.kl.join() ) {
evt.target.removeEventListener( "keyup", knm, false );


/* Although at this point we wish to remove a listener
we could easily have had multiple "keyup" listeners
each triggering different functions, so we MUST
say which function we no longer wish to trigger
rather than which listener we wish to remove.


Normal scoping will apply to where we can mention this function
and thus, where we can remove the listener set to trigger it. */


document.body.classList.add( "konami" );
}
}, false );
document.body.removeChild( document.getElementById( "konami" ) );
</script>

这允许一个有效的匿名函数结构,避免使用 实际上是反对的,并允许轻松删除。

顺便说一句 : 在设置侦听器之后立即删除 script 元素是一个可爱的技巧,因为隐藏代码对于窥探者来说并不明显(会破坏惊喜的; -)

所以方法(更简单)是:

element.addEventListener( action, function name () {
doSomething();
element.removeEventListener( action, name, capture );
}, capture );
window.document.onkeydown = function(){};
window.document.removeEventListener("keydown", getEventListeners(window.document.keydown[0].listener));

可能是几个匿名函数,keydown1

警告: 只能在 Chrome Dev Tools中工作并且不能在代码 中使用: < a href = “ https://stackoverflow. com/a/46974805/2528761”> 链接

这并不理想,因为它删除了所有,但可能适合您的需要:

z = document.querySelector('video');
z.parentNode.replaceChild(z.cloneNode(1), z);

复制节点的所有属性及其值,包括 内部(行内)侦听器。它不复制使用以下方法添加的事件侦听器 AddEventListener ()

CloneNode ()

JavaScript : addEventListener 方法在它调用的 EventTarget (Element | document | Window)上注册指定的侦听器。

AddEventListener(Event _ type,handler _ function,冒泡 | 捕捉) ;

鼠标,键盘 事件 WebConsole 中的示例测试:

var keyboard = function(e) {
console.log('Key_Down Code : ' + e.keyCode);
};
var mouseSimple = function(e) {
var element = e.srcElement || e.target;
var tagName = element.tagName || element.relatedTarget;
console.log('Mouse Over TagName : ' + tagName);
};
var  mouseComplex = function(e) {
console.log('Mouse Click Code : ' + e.button);
}


window.document.addEventListener('keydown',   keyboard,      false);
window.document.addEventListener('mouseover', mouseSimple,   false);
window.document.addEventListener('click',     mouseComplex,  false);

RemoveEventListener 方法移除以前注册在 EventTarget.addEventListener ()中的事件侦听器。

window.document.removeEventListener('keydown',   keyboard,     false);
window.document.removeEventListener('mouseover', mouseSimple,  false);
window.document.removeEventListener('click',     mouseComplex, false);

犬科动物

为了对此提供一种更新的方法:

//one-time fire
element.addEventListener('mousedown', {
handleEvent: function (evt) {
element.removeEventListener(evt.type, this, false);
}
}, false);

在严格模式下工作的 奥托 · 纳斯卡雷拉解决方案的一个版本是:

button.addEventListener('click', function handler() {
///this will execute only once
alert('only once!');
this.removeEventListener('click', handler);
});

可能不是最好的解决方案,就你的要求而言。我还没有确定一个有效的方法来删除在事件侦听器调用中内联声明的匿名函数。

我个人使用一个变量来存储 <target>,并在事件侦听器调用之外声明函数,例如:

const target = document.querySelector('<identifier>');

function myFunc(event) { function code; }

target.addEventListener('click', myFunc);

然后移除监听器:

target.removeEventListener('click', myFunc);

这不是您将收到的最好的建议,但是要删除匿名函数,我发现唯一有用的解决方案是删除然后替换 HTML 元素。我确信一定有一个更好的普通 JS 方法,但我还没有看到它。

我偶然发现了同样的问题,这是我能找到的最好的解决办法:

/*Adding the event listener (the 'mousemove' event, in this specific case)*/
element.onmousemove = function(event) {
/*do your stuff*/
};
/*Removing the event listener*/
element.onmousemove = null;

请记住,我只测试了 window元素和 'mousemove'事件,所以这种方法可能会有一些问题。

在现代浏览器中,你可以做到以下几点..。

button.addEventListener( 'click', () => {
alert( 'only once!' );
}, { once: true } );

Https://developer.mozilla.org/en-us/docs/web/api/eventtarget/addeventlistener#parameters

我知道这是一个相当古老的线索,但我想我可以把我的两分钱,对那些谁觉得它有用。

脚本(抱歉没有创造性的方法名称) :

window.Listener = {
_Active: [],
remove: function(attached, on, callback, capture){
for(var i = 0; i < this._Active.length; i++){
var current = this._Active[i];
if(current[0] === attached && current[1] === on && current[2] === callback){
attached.removeEventListener(on, callback, (capture || false));
return this._Active.splice(i, 1);
}
}
}, removeAtIndex(i){
if(this._Active[i]){
var remove = this._Active[i];
var attached = remove[0], on = remove[1], callback = remove[2];
attached.removeEventListener(on, callback, false);
return this._Active.splice(i, 1);
}
}, purge: function(){
for(var i = 0; i < this._Active.length; i++){
var current = this._Active[i];
current[0].removeEventListener(current[1], current[2]);
this._Active.splice(i, 1);
}
}, declare: function(attached, on, callback, capture){
attached.addEventListener(on, callback, (capture || false));
if(this._Active.push([attached, on, callback])){
return this._Active.length - 1;
}
}
};

你可以这样使用它:

// declare a new onclick listener attached to the document
var clickListener = Listener.declare(document, "click" function(e){
// on click, remove the listener and log the clicked element
console.log(e.target);
Listener.removeAtIndex(clickListener);
});


// completely remove all active listeners
// (at least, ones declared via the Listener object)
Listener.purge();


// works exactly like removeEventListener
Listener.remove(element, on, callback);

我在使用防拷贝 wordpress 插件时也遇到过类似的问题,代码是:

function disableSelection(target){
if (typeof target.onselectstart!="undefined") //For IE
target.onselectstart=function(){return false}
else if (typeof target.style.MozUserSelect!="undefined") //For Firefox
target.style.MozUserSelect="none"
else //All other route (For Opera)
target.onmousedown=function(){return false}
target.style.cursor = "default"
}

然后它是由一个松散的放置

<script type="text/javascript">disableSelection(document.body)</script>.

我只是通过在这个事件上附加其他匿名函数来解决这个问题:

document.body.onselectstart = function() { return true; };

除了 Safari 之外,大多数流行浏览器的最新版本都支持一种新的方法。

检查 犬科动物以获得更新的支持。

更新: 现在也支持 Sefari (版本15 ^)。

我们可以向 addEventListner添加一个名为 signal的选项,并从 AbortController中分配一个 signal,以后可以在 AbortController上调用 abort()方法。

这里有一个例子。

我们创建一个 AbortController:

const controller = new AbortController();

然后我们创建 eventListner并传入选项 signal:

document.addEventListener('scroll',()=>{
// do something
},{signal: controller.signal})

然后在稍后的时间移除 eventListner,我们调用:

controller.abort()

设置匿名监听器:

document.getElementById('ID').addEventListener('click', () => { alert('Hi'); });

删除匿名监听器:

document.getElementById('ID').removeEventListener('click',getEventListeners(document.getElementById('ID')).click[0].listener)

使用终止控制器,整洁干净

附加事件侦听器

const el = document.getElementById('ID')
const controller = new AbortController;
el.addEventListener('click',() => {
console.log("Clicked")
},{signal: controller.signal})

当要删除事件侦听器时

controller.abort()

实现这一点的另一个替代解决方案是添加一个空事件处理程序并防止事件传播。

让我们假设您需要从一个具有 #specific-div id 的元素中删除 mouseleave事件处理程序,该元素是用一个匿名函数添加的,而且您不能使用 removeEventListener(),因为您没有函数名。

您可以向该元素添加另一个事件处理程序并使用 event.stopImmediatePropagation(),为了确保这个事件处理程序在现有的事件处理程序之前工作,您应该将第三个参数(使用捕获)作为 true传递。

最终代码应该如下所示:

document.getElementById("specific-div")
.addEventListener("mouseleave", function(event) {
event.stopImmediatePropagation()
}, true);

这可能对某些特定的情况有所帮助,您不能选择 cloneNode()方法。