質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

444閲覧

イベントハンドラ内でremoveEventListenerを実行したい

ojako

総合スコア6

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2023/01/30 13:10

前提

Javascriptでトランプゲームを作成していて、イカサマイベントを実装しています。
そこでイカサマClassを作成しイベントを発火させ、カードに触れられないようにクリックイベントを削除したいのですが、うまくいかないです。
トランプゲームは、
・メインのゲームの進行クラスであるmain.js
・イベントリスナーなどの汎用関数をまとめたUtil.js
・イベントハンドラ等があるikasama.js
・カードを選択するプレイヤークラス
カードを選択するメソッドはプレイヤークラスですが、それを実行するのはメインの進行クラスである、main.jsです。
このイベントを削除したいです。

発生している問題

特にエラーメッセージなどは出ていません。
検証ツールでデバックしてみると、removeEventListenerの「handler」にはイベントを登録したmain.jsのメンバメソッドが渡ってきているようでした。

this.clickEvent : ƒ #onClickCard() [[FunctionLocation]] : main.js:110

ソースコード(汎用関数)

util.js

1export default class Util { 2 /** 3 * 指定した時間だけ待つ(未指定の場合は1秒) 4 */ 5 static sleep = (wait = 1000) => { 6 return new Promise((resolve, reject) => { 7 setTimeout(() => resolve(), wait); 8 }); 9 }; 10 11 /** 12 * イベントハンドラの追加 13 */ 14 static addEventListener = (selector, event, handler) => { 15 document 16 .querySelectorAll(selector) 17 .forEach((e) => e.addEventListener(event, handler)); 18 }; 19 /** 20 * イベントハンドラを削除する 21 */ 22 static removeEventListener = (selector, event, handler) => { 23 document 24 .querySelectorAll(selector) 25 .forEach((e) => e.removeEventListener(event, handler)); 26 }; 27}

ソースコード(ゲームクラス)

main.js

1import Util from "./util.js"; 2import Player from "./player.js"; 3import Com from "./com.js"; 4import Card from "./card.js"; 5import Pair from "./pair.js"; 6import Ikasama from "./ikasama.js"; 7/** 8 * Gameクラス 9 */ 10export default class Game { 11 #you; //あなた(You) 12 #com; // コンピュータ 13 #cards; // 山札のカード 14 #isRunning; // ゲームの実行状態 15 /** 16 * コンストラクタ 17 */ 18 constructor() { 19 this.#you = null; 20 this.#com = null; 21 this.#cards = []; 22 this.#isRunning = false; 23 this.#setUpEvent(); 24 } 25 run() { 26 this.#initialize(); 27 } 28 /** 29 * ゲームの状態を初期化する 30 */ 31 #initialize() { 32 // ①プレイヤーを生成する 33 this.#you = new Player(".card.you"); 34 this.#com = new Com(".card.com"); 35 // ランダムイベントの抽選 36 if (Util.randomEvent(8)) { 37 this.#ikasamaActive(); 38 } 39 } 40 41 /** 42 * 手札のクリックイベントハンドラ 43 */ 44 #onClickCard() { 45 if (this.#isRunning) { 46 this.#you.selectCard(event.target); 47 } 48 } 49 /** 50 * イカサマウィンドウの振る舞い 51 */ 52 #ikasamaActive() { 53 // ウィンドウを表示する 54 Ikasama.displayWindow(); 55 // イカサマを実行する 56 Util.addEventListener("#intikiOn", "click", {player: this.#you, clickEvent: this.#onClickCard, handleEvent: Ikasama.destinyCard}); 57 // イカサマするのをやめる 58 Util.addEventListener("#intikiNo", "click", Ikasama.goodBye); 59 } 60 /** 61 * イベントハンドラを登録する 62 */ 63 #setUpEvent() { 64 Util.addEventListener(".card.you", "click", this.#onClickCard.bind(this)); 65 } 66} 67

player.js

1//...一部抜粋 2selectCard(node) { 3 node.classList.toggle("selected"); 4 };

ソースコード(イカサマクラス)

ikasama.js

1import Util from "./util.js"; 2 3export default class Ikasama { 4 /** 5 * イカサマの選択を迫る 6 */ 7 static displayWindow() { 8 document.querySelector('.ikasama').classList.add('active'); 9 } 10 /** 11 * イカサマを発動する 12 */ 13 static async destinyCard() { 14 document.querySelector(".ikasama").classList.remove("active"); 15 await Util.sleep(); 16 if(Util.randomEvent(4)) { 17 this.player.cards.forEach((card, index) => { 18 card.rank = 10 + index; 19 card.suit = 1; 20 card.index = 10 + index; 21 if(index === 4) card.index = 1; 22 }); 23 } else { 24 this.player.cards.forEach((card, index) => { 25 card.rank = 1 + index; 26 if((index + 1) % 2 === 0) card.rank = 5 + index; 27 card.suit = 1 + index; 28 if (index === 4) card.suit = 1; 29 switch (index) { 30 case 0: 31 card.index = 1; 32 break; 33 case 1: 34 card.index = 19; 35 break; 36 case 2: 37 card.index = 29; 38 break; 39 case 3: 40 card.index = 47; 41 break; 42 case 4: 43 card.index = 5; 44 break; 45 } 46 }); 47 } 48 this.player.sortCards(); 49 50 /** 51 * イベントリスナーを解除しようとしてうまく行かず保留。 52 * 試したこと:登録してある関数の参照を取得。mainメソッドで直接指定。 53 */ 54 Util.removeEventListener(".card.you", "click", this.clickEvent); 55 alert("自分のカードをすり替えました!!\n※このまま勝負してください。"); 56 }; 57}

以上です。
どうかよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

解決方法

結果から言うと、bind(this)でコールバック関数を渡していたことが原因でした。
解決方法はクラスのプロパティとしてバインドしたコールバック関数を変数にして、そちらを参照するようにしました。

イベントを登録するときのイベントハンドラーを検証ツールでみてみると、「binding #onClickCard」となっていて、参照先が別の関数扱いになっていたようです。

main.js

1#callbackEvent; // バインドしたコールバック関数 2constructor() { 3 this.#you = null; 4 this.#com = null; 5 this.#callbackEvent = this.#onClickCard.bind(this); 6 this.#setUpEvent(); 7 } 8Util.EventListener("#intikiOn", { 9 player: this.#you, 10 clickEvent: this.#callbackEvent, 11 handleEvent: Ikasama.destinyCard, 12 }); 13Util.EventListener(".card.you", this.#callbackEvent);

投稿2023/01/30 23:03

ojako

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問