是否可以使用 addEventListener 调用类方法?

Is it possible to call a class method with addEventListener?

提问人:Azrael 提问时间:1/23/2014 最后编辑:Azrael 更新时间:3/7/2023 访问量:29089

问:

只是我一直在想的事情。在方法的第二个参数中,是否可以调用“(自定义)类方法”而不是函数?.addEventListener

即像下面这样的东西会起作用吗?

var object = new ClassName();
document.getElementById('x').addEventListener('click', object.method, false);
JavaScript的

评论

3赞 cookie monster 1/23/2014
取决于你所说的“工作”是什么意思。你试过吗?如何/在哪里定义?它需要做什么?它可能“有效”,也可能不“有效”。method
0赞 Azrael 1/23/2014
代码就在我的脑海中。我还没有测试过。我以前从未接触过 JavaScript 中的 OOP,所以这只是我想知道的事情。
0赞 cookie monster 1/23/2014
那么答案是“也许”。如果确实是一个函数,它将作为处理程序传递,但在不知道它做什么的情况下,它可能会也可能不会“工作”。.method
0赞 Felix Kling 1/23/2014
请注意,没有“自定义类方法”这样的东西。 仍然是一个正常的函数,它看起来就像任何其他函数一样。函数与作为属性值分配给它的对象之间没有隐式关系。想象一下你有.那么,按照你的逻辑,现在是什么?它“属于”什么?object.methodaddEventListenerfunction foo() {...}; obj.method = foo; obj2.method2 = foo; var bar = foo;foo
0赞 Azrael 1/23/2014
我所说的“自定义类方法”是指内置方法以外的任何方法。因此引号。对不起,如果这令人困惑。

答:

0赞 S. A. 1/23/2014 #1

是的。这是可能的,只要注意上下文即可。F.D.(英语:F.D.)

ClassName.prototype.click_handler = function(el) {
    // Here 'this' doesn't refer to the instance
    // of ClassName but to the element clicked
}
var object = new ClassName();

document.getElementById('x').addEventListener('click', object.click_handler, false);

评论

0赞 cookie monster 1/23/2014
@rvighne:你对这个答案做了一个非常彻底的改变。
0赞 rvighne 1/23/2014
@cookiemonster 不是的。最初的答案是好的,但它抛出了一个 JavaScript 错误(你不能设置实例的原型)。显然我们不能那样做。我相信这符合塞尔吉奥的意图。
0赞 cookie monster 1/23/2014
右。它从根本上改变了答案的含义,变成了完全不同的东西。
0赞 S. A. 1/23/2014
@rvighne感谢您的编辑建议。我不知道我在想什么!
31赞 user229044 1/23/2014 #2

不,你写的东西是行不通的,因为如果没有上下文,就会被调用。在里面,将设置为启动事件的 DOM 元素。methodobjectmethodthis

如果要调用该方法并保留上下文,请使用函数关闭变量:object

var object = new ClassName();
document.getElementById('x').addEventListener('click', function () {
  object.method()
}, false);

评论

1赞 RobG 1/23/2014
+1 你可能知道这一点,但为了 OP 的利益,我还是会发表评论。这不是“上下文”,而是执行上下文的参数。对于函数,它由函数的调用方式(或使用 bind)进行设置。它可以设置为任何对象(或严格模式下的任何值)。.
5赞 Giovanni 6/2/2016
那么如何删除相同的事件侦听器呢?这就是我现在的挑战。
4赞 Giovanni 6/2/2016
这为我解决了这个问题:stackoverflow.com/questions/9720927/......
1赞 Radio 4/9/2015 #3

这里的答案很有帮助,但仍然让我想知道是否有一种整洁的语法可以做基本相同的事情。我不想将对类实例的引用传递给它自己,这很奇怪。

这是一个整洁的模式,它将所有内容保留在类中,无需使用实例引用,而是使用闭包。

myclass= function(){};
myclass.prototype.addSystemEvents = function(){
  var scope = this;
  window.addEventListener( 'resize', function(){scope.onWindowResize();}, false);
}
myclass.prototype.onWindowResize = function(){
   //do whatever
}

评论

1赞 Marius 6/8/2020
在您的类中: window.addEventListener(“keydown”,(e)=>this.keyDown(e));
1赞 Erick Ribeiro 4/30/2020 #4

是的,这是可能的。您需要调用该方法并保留上下文,使用函数关闭对象变量:

var object = new ClassName();
document.getElementById('x').addEventListener('click', function (e) {
  object.method(e)
}, false);

如果您在没有内部函数的情况下调用,则“this”将被设置为启动事件的 DOM 元素。

评论

0赞 Ram Shankar Kumar 2/20/2022
你能向我解释一下,当我们用函数关闭对象变量时,上下文是如何改变的吗?早些时候,它将上下文作为启动事件的 DOM 元素发送,但使用函数结束会更改上下文,但如何更改?
3赞 acarlstein 5/2/2021 #5

是的,通过执行绑定是可能的。

下面,我将创建一个 Web 组件。大多数浏览器都支持的功能。

为了创建此 Web 组件,我正在创建一个扩展该类的类。就 JavaScript 而言,这只是另一个常规类。HTMLElement

现在,我希望我的 Web 组件像按钮一样运行。 我希望每次点击我的标签时增加一个计数器。

注意:这三个点表示“更多代码”到达那里。

因此,我创建了一个变量,该变量将在构造函数中保存计数:

constructor(){
  ...
  this.count = 0;
  ...

然后,我添加一个侦听器,用于检测何时单击我的 Web 组件并调用该方法:onClick

constructor(){
  ...
  this.count = 0;
  ...
  this.addEventListener('click', this.onClick, false);        
}

onClick(event){
 let prevCount = this.count;
 this.count++;    
 let msg = `Increased Count from ${prevCount} to ${this.count}`;
 document.getElementById("log").innerHTML += `${msg}<br/>`;     
 }

onClick 旨在增加计数器并在计数器中打印上一个值和当前值;但是,这里有一个问题!!

问题出在这一行.关键字不是指类的实例。原因是添加的函数会将绑定元素引用为 ,而不是函数或对象。this.count++;thisHTMLExampleaddEventListenerthis

因此,您必须通过添加以下代码行来绑定该函数,该函数由 用于类的实例:addEventListener

this.onClick = this.onClick.bind(this);

现在,当您在方法中使用关键字时,将引用类的实例。thisonClickthisHTMLExample

请检查下面的代码并运行它。我认为这样会变得很清楚:

class HTMLExample extends HTMLElement{
  constructor(){
    super();
    this.count = 0;
    this.onClick = this.onClick.bind(this);
    this.addEventListener('click', this.onClick, false);        
  }
  
  onClick(event){
    let prevCount = this.count;
    this.count++;    
    let msg = `Increased Count from ${prevCount} to ${this.count}`;
    document.getElementById("log").innerHTML += `${msg}<br/>`;     
  }
}
customElements.define('example-component', HTMLExample);
example-component{
  cursor: pointer;
  border: 1px solid black;
  background: lightgray;
  padding: 2px;
}
<example-component>Button</example-component>
<div id="log"></div>

18赞 OriginalHacker 7/9/2021 #6

我只是尝试了一种更直接的方法,它似乎有效,我会说它很干净。我只是将参数添加到 .不要让它变得复杂,当它不是......bind(this)addEventListener()

class HTMLExample extends HTMLElement{
  constructor(){
    super();
    this.count = 0;
    this.addEventListener('click', this.onClick.bind(this), false);        
  }
  
  onClick(event){
    let prevCount = this.count;
    this.count++;    
    let msg = `Increased Count from ${prevCount} to ${this.count}`;
    document.getElementById("log").innerHTML += `${msg}<br/>`;     
  }
}
0赞 user3413723 11/28/2022 #7

对于任何使用打字稿或 Babel/Transpilation 的人来说,这是我能想到的最干净的方法,我相信还有改进的余地!

class Person {
    name = "bobby"
    sayGoodbyBound = this.sayGoodby.bind(this);
    sayGoodby() {
        console.log('Goodbye, my name is', this.name);
    }
}

const person = new Person();
let element = document.createElement("button")
element.addEventListener("click", person.sayGoodbyBound);

element.click()

// remove same one
element.removeEventListener("click", person.sayGoodbyBound);

2赞 9re 3/7/2023 #8

大多数答案都使用 Function.prototype.bind(),但您可以通过简单地编写来实现它。

class EventHandler {
  constructor(element) {
    element.addEventListener('mousedown', this.handler); 
  }
  // just declare the method as a property with arrow function.
  hander = () => {
    console.log(this);
  }
}

我在 codepen.io 编写了完整的工作代码示例。

评论

0赞 Richard Peck 11/22/2023
这效果很好,谢谢!