Estoy creando un juego de cartas en HTML, CSS, JS y tengo una clase PlayerHand que contiene las funciones raiseCard() , lowerCard() , addCards() entre otras. Cuando uso addCards() , las imágenes SVG se agregan esencialmente al HTML y asigno un controlador de clics a cada una de las tarjetas.
El controlador de clics en las cartas usa las funciones raiseCard() y lowerCard() de PlayerHand y también necesita saber en qué carta se hizo clic, para saber qué carta subir o bajar. El problema que tengo es que cuando defino clickHandler dentro de la clase PlayerHand , no puedo usar this palabra clave para acceder a las funciones de clase lowerCard() y raiseCard() . Porque this va a ser la tarjeta en la que hice clic. Soy consciente de bind , pero aún necesito poder saber en qué tarjeta se hizo clic y acceder a las funciones de clase.
¿Alguna idea de cómo puedo hacer esto? ¿Quizás estoy diseñando esto de una manera estúpida?
class PlayerHand { addCards(cards, eventHandler = null) { if (cards.length + this.getCards() > this.MAX_CARDS_ON_HAND) return; // Don't allow more than 13 cards on hand cards.forEach((cid) => { const card = document.createElement("card-t"); card.setAttribute("cid", cid); card.addEventListener("click", eventHandler, false); this.container.appendChild(card); }); } raiseCard(cardElement) { cardElement.style.transform = "translate(0px, calc(var(--raise-card-on-click) * -1))"; } lowerCard(cardElement) { cardElement.style.transform = "none"; } cardClickHandler() { const LOWERED = 0; let cardHeight = LOWERED; const transform = this.style.transform.match(/\d+/g); // Get X and Y coordinate if (transform !== null) cardHeight = transform["1"]; // Get the Y coordinate if (cardHeight === LOWERED) { thisClass.raiseCard(thisCard); // I need to access the class function and pass in the card object that was clicked } else { thisClass.lowerCard(thisCard); // I need to access the class function and pass in the card object that was clicked } } } Otro método que probé fue definir clickHandler fuera de la clase PlayerHand y luego usaría el objeto del player dentro del controlador de clic, pero tampoco me gustó mucho, ya que no es muy dinámico al definir el objeto dentro del clickHandler estáticamente.
player = new PlayerHand(); function clickHandler() { ... if (cardHeight === LOWERED) { player.raiseCard(this); } else { player.lowerCard(this); } }Simplemente podría vincular la tarjeta que desea recuperar con el argumento de la función del controlador de clics:
class PlayerHand { addCards(cards, eventHandler = null) { // ... cards.forEach((cid) => { const card = document.createElement("card-t"); card.setAttribute("cid", cid); card.addEventListener("click", this.cardClickHandler.bind(this, card), false); this.container.appendChild(card); }); } // ... cardClickHandler(_event, card) { const LOWERED = 0; let cardHeight = LOWERED; const transform = this.style.transform.match(/\d+/g); // Get X and Y coordinate if (transform !== null) cardHeight = transform["1"]; // Get the Y coordinate if (cardHeight === LOWERED) { this.raiseCard(card); // retrieve here the card you passed as argument in the event handler } else { this.lowerCard(card); // idem } } }Como básicamente necesita dos objetos (el elemento de tarjeta y la instancia de PlayerHand ), necesitará dos argumentos: uno puede ser this , pero el otro debe ser un argumento normal. Como cardClickHandler se define como un método en el prototipo de PlayerHand , sería más natural dejar que this sea la instancia de PlayerHand .
Así que adjunte el controlador de eventos de la siguiente manera:
card.addEventListener("click", () => eventHandler.call(this, card), false);Y entonces el método sería algo como:
cardClickHandler(card) { const LOWERED = 0; let cardHeight = LOWERED; const transform = card.style.transform.match(/\d+/g); if (transform !== null) cardHeight = transform["1"]; if (cardHeight === LOWERED) { this.raiseCard(card); } else { this.lowerCard(card); } }Cuando vincula argumentos a una función, se anteponen a los argumentos proporcionados por la persona que llama. Entonces card será el primer argumento de cardClickHandler() , antes de _event proporcionado por addEventListener() .
class PlayerHand { addCards(cards, eventHandler = null) { // ... cards.forEach((cid) => { const card = document.createElement("card-t"); card.setAttribute("cid", cid); card.addEventListener("click", this.cardClickHandler.bind(this, card), false); this.container.appendChild(card); }); } // ... cardClickHandler(card, _event) { const LOWERED = 0; let cardHeight = LOWERED; const transform = this.style.transform.match(/\d+/g); // Get X and Y coordinate if (transform !== null) cardHeight = transform["1"]; // Get the Y coordinate if (cardHeight === LOWERED) { this.raiseCard(card); // retrieve here the card you passed as argument in the event handler } else { this.lowerCard(card); // idem } } }