JavaScript类和事件监听器

I'm trying to use JavaScript class architecture in combination with addEventListener such that I can define a series of class methods once, which will be applied to all appropriate HTML and/or CSS objects. Below is an example with ONLY one circle, which should toggles red or blue when clicked. Unfortunately, as is, the class does architecture is unable to properly communicate with the DOM.

我选择内联编写脚本只是为了更轻松地探索基本概念,而不是为了问题衔接而四处浏览多个文件(我意识到,实际上,我可能会使用单独的HTML和JS文件。)

我想按原样进行编码,以便单击时圆圈会更改颜色。 (此外,不使用类体系结构时的代码DID函数。如果有用,可以添加它。)

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.circle {
  height: 50px;
  width: 50px;
  background-color: #555;
  border-radius: 50%;
}
</style>
</head>
<body>

<h2>Circle CSS</h2>
<div class="circle"></div>
<script>

class GameObject{
  constructor(shape){
    this.shape = shape;
    this.clicks = 0;
  };
  clickEvent(){
    this.shape.addEventListener('click',function(){
      this.clicks += 1
      if (this.clicks % 2 == 1){
        this.shape.style.backgroundColor = 'red';
      }else{
        this.shape.style.backgroundColor = 'blue';
      }
    })
  };
};

let shape = document.querySelector('.circle')
let s = new GameObject(shape);

console.log(s);
</script>

</body>
</html>

Also, the following questions/answers went above my head, though they are related: Javascript Class & EventListener Dealing with Scope in Object methods containing 'this' keyword called by Event Listeners

Edit: I took advice from comment and added clickEvent() into this constructor. However, the following error was triggered:

Uncaught TypeError: Cannot read property 'style' of undefined
    at HTMLDivElement.<anonymous> (circle.html:31)
评论
  • gquia
    gquia 回复

    1. You never call the function clickEvent.
    2. The handler of addEventListener uses its own context, to solve this you can either declare a variable let that = this and then use it inside of the handler, or you can use an arrow function in order to use the right context (instance of GameObject).

    这种方法使用箭头功能

    <html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
    .circle {
      height: 50px;
      width: 50px;
      background-color: #555;
      border-radius: 50%;
    }
    </style>
    </head>
    <body>
    
    <h2>Circle CSS</h2>
    <div class="circle"></div>
    <script>
    
    class GameObject{
      constructor(shape){
        this.shape = shape;
        this.clicks = 0;
      };
      clickEvent(){
        this.shape.addEventListener('click',() => {
          this.clicks += 1
          if (this.clicks % 2 == 1){
            this.shape.style.backgroundColor = 'red';
          }else{
            this.shape.style.backgroundColor = 'blue';
          }
        })
      };
    };
    
    let shape = document.querySelector('.circle')
    let s = new GameObject(shape);
    s.clickEvent();
    
    console.log(s);
    </script>
    
    </body>
    </html>

  • SOS
    SOS 回复

    <html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
    .circle {
      height: 50px;
      width: 50px;
      background-color: #555;
      border-radius: 50%;
    }
    </style>
    </head>
    <body>
    
    <h2>Circle CSS</h2>
    <div class="circle"></div>
    <script>
    
    class GameObject{
      constructor(shape){
        this.shape = shape;
        this.clicks = 0;
        this.clickEvent(); // call the method to add the listener
      };
      clickEvent(){
        this.shape.addEventListener('click',function(){
          this.clicks += 1
          if (this.clicks % 2 == 1){
            this.shape.style.backgroundColor = 'red';
          }else{
            this.shape.style.backgroundColor = 'blue';
          }
        }.bind(this)) // bind callback function to the the correct 'this' context
      };
    };
    
    let shape = document.querySelector('.circle')
    let s = new GameObject(shape);
    
    console.log(s);
    </script>
    
    </body>
    </html>

  • 雪
    回复

    Change the name clickEvent to handleEvent, and move the .addEventListener call outside the class. Then pass your game object as the event handler, and it'll work.

    class GameObject {
      constructor(shape) {
        this.shape = shape;
        this.clicks = 0;
      };
      handleEvent() {
        this.clicks += 1
        if (this.clicks % 2 == 1) {
          this.shape.style.backgroundColor = 'red';
        } else {
          this.shape.style.backgroundColor = 'blue';
        }
    
        console.log(this);
      };
    };
    
    let shape = document.querySelector('.circle')
    let s = new GameObject(shape);
    
    shape.addEventListener("click", s);
    
    console.log(s);
    .circle {
      height: 50px;
      width: 50px;
      background-color: #555;
      border-radius: 50%;
    }
    <h2>Circle CSS</h2>
    <div class="circle"></div>