使用纯 JavaScript 取消绑定事件委托的多参数事件侦听器
Unbind an event-delegated, multi-argument event listener with plain JavaScript
我有一个问题已被不同的答案触及,但据我所知,其细节与我要求的不同。我希望取消绑定一个事件侦听器,但有一些限制。
- 事件委托给子项
- 事件侦听器采用次要参数
- 事件函数必须在 if 子句中解除自身绑定
我把它简化为下面的例子。当您单击第一个按钮时,您可以单击任何其他按钮。第一个按钮的文本将相应更改。但是,因为永远不会删除事件侦听器,所以您可以不断更改您的“选择”并单击任何其他按钮。我想要的是,当您单击第一个按钮时,您只能单击另一个按钮,然后删除侦听器。实际上,这意味着如果你想改变你的“选择”,你首先需要再次点击第一个按钮,然后重新附加事件监听器。
const btn = document.querySelector("button")
const div = document.querySelector("div")
function listen(text, evt) {
if (evt.target.tagName == "BUTTON") {
btn.textContent = text + evt.target.textContent
// Unbind listen function from div so that that `btn` must be clicked every time
// you want to change the selected button.
// The following does NOT work.
div.removeEventListener("click", this)
}
}
btn.addEventListener("click", evt => {
div.addEventListener("click", listen.bind(this, "I selected "))
})
<button>Click me</button>
<div>
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</div>
如您所见,我尝试删除事件侦听器,但由于我使用了 bind
(使第二个参数起作用),我认为 this
不再是相同的引用。我怎样才能在不依赖其他库的情况下让它工作?
this
无论如何都不会奏效。它通常指的是处理程序绑定到的 DOM 元素,而不是函数本身。
你可以用不同的方式解决这个问题。一种可能性是引入一个用于绑定事件处理程序的帮助程序,这反过来会将“删除”功能传递给处理程序。
const btn = document.querySelector("button")
const div = document.querySelector("div")
function addEventListener(element, type, handler, ...args) {
const handlerWrapper = function(event) {
return handler.call(this, event, remove);
};
const remove = () => element.removeEventListener(type, handlerWrapper);
element.addEventListener(type, handlerWrapper, ...args);
}
function listen(text, evt, remove) {
if (evt.target.tagName == "BUTTON") {
btn.textContent = text + evt.target.textContent
// Unbind listen function from div so that that `btn` must be clicked every time
// you want to change the selected button.
remove();
}
}
btn.addEventListener("click", evt => {
addEventListener(div, "click", listen.bind(this, "I selected "))
})
<button>Click me</button>
<div>
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</div>
话虽如此,如果您总是希望最多执行一个事件处理程序一次,请在绑定事件处理程序时传递once: true
option。
我有一个问题已被不同的答案触及,但据我所知,其细节与我要求的不同。我希望取消绑定一个事件侦听器,但有一些限制。
- 事件委托给子项
- 事件侦听器采用次要参数
- 事件函数必须在 if 子句中解除自身绑定
我把它简化为下面的例子。当您单击第一个按钮时,您可以单击任何其他按钮。第一个按钮的文本将相应更改。但是,因为永远不会删除事件侦听器,所以您可以不断更改您的“选择”并单击任何其他按钮。我想要的是,当您单击第一个按钮时,您只能单击另一个按钮,然后删除侦听器。实际上,这意味着如果你想改变你的“选择”,你首先需要再次点击第一个按钮,然后重新附加事件监听器。
const btn = document.querySelector("button")
const div = document.querySelector("div")
function listen(text, evt) {
if (evt.target.tagName == "BUTTON") {
btn.textContent = text + evt.target.textContent
// Unbind listen function from div so that that `btn` must be clicked every time
// you want to change the selected button.
// The following does NOT work.
div.removeEventListener("click", this)
}
}
btn.addEventListener("click", evt => {
div.addEventListener("click", listen.bind(this, "I selected "))
})
<button>Click me</button>
<div>
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</div>
如您所见,我尝试删除事件侦听器,但由于我使用了 bind
(使第二个参数起作用),我认为 this
不再是相同的引用。我怎样才能在不依赖其他库的情况下让它工作?
this
无论如何都不会奏效。它通常指的是处理程序绑定到的 DOM 元素,而不是函数本身。
你可以用不同的方式解决这个问题。一种可能性是引入一个用于绑定事件处理程序的帮助程序,这反过来会将“删除”功能传递给处理程序。
const btn = document.querySelector("button")
const div = document.querySelector("div")
function addEventListener(element, type, handler, ...args) {
const handlerWrapper = function(event) {
return handler.call(this, event, remove);
};
const remove = () => element.removeEventListener(type, handlerWrapper);
element.addEventListener(type, handlerWrapper, ...args);
}
function listen(text, evt, remove) {
if (evt.target.tagName == "BUTTON") {
btn.textContent = text + evt.target.textContent
// Unbind listen function from div so that that `btn` must be clicked every time
// you want to change the selected button.
remove();
}
}
btn.addEventListener("click", evt => {
addEventListener(div, "click", listen.bind(this, "I selected "))
})
<button>Click me</button>
<div>
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</div>
话虽如此,如果您总是希望最多执行一个事件处理程序一次,请在绑定事件处理程序时传递once: true
option。