You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加DOM事件监听器后图片不显示,JS拖拽拼图游戏开发问题

解决JS拖拽拼图游戏中populateBoard失效问题

问题根源

你直接将类的dragStart、dragDrop等方法作为事件监听函数绑定给tile时,函数内部的this会指向触发事件的<img>元素,而非PuzzleGame实例。当这些方法尝试访问实例的currTile、otherTile属性时,会因上下文错误抛出异常,导致populateBoard的循环中断,最终棋盘无法填充。


修复方案一:绑定正确的this上下文

在添加事件监听器时,用bind(this)确保方法内部的this指向当前游戏实例:

populateBoard() {
  for (let r = 0; r < this.rows; r++) {
    for (let c = 0; c < this.columns; c++) {
      let tile = document.createElement("img");
      tile.id = r.toString() + "-" + c.toString();
      tile.src = "./images/" + this.randomOrder.shift() + ".png";
      // 绑定正确的this上下文
      tile.addEventListener("dragstart", this.dragStart.bind(this));
      tile.addEventListener("dragover", this.dragOver.bind(this));
      tile.addEventListener("dragenter", this.dragEnter.bind(this));
      tile.addEventListener("dragleave", this.dragLeave.bind(this));
      tile.addEventListener("drop", this.dragDrop.bind(this));
      tile.addEventListener("dragend", this.dragEnd.bind(this));

      document.getElementById("board").append(tile);
    }
  }
}

同时调整事件方法逻辑,用e.target获取事件对应的tile元素:

dragStart(e) {
  this.currTile = e.target; // 获取被拖拽的图片元素
}
dragDrop(e) {
  this.otherTile = e.target; // 获取被放置的图片元素
}
dragEnd() {
  let currImg = this.currTile.src;
  let otherImg = this.otherTile.src;
  this.currTile.src = otherImg;
  this.otherTile.src = currImg;
}

修复方案二:单独编写assignEvents函数(符合你的推测)

先完成棋盘填充,再遍历所有tile绑定事件,避免填充过程中因事件绑定错误中断:

  1. 修改populateBoard,移除事件绑定代码:
populateBoard() {
  for (let r = 0; r < this.rows; r++) {
    for (let c = 0; c < this.columns; c++) {
      let tile = document.createElement("img");
      tile.id = r.toString() + "-" + c.toString();
      tile.src = "./images/" + this.randomOrder.shift() + ".png";
      document.getElementById("board").append(tile);
    }
  }
}
  1. 添加assignEvents方法:
assignEvents() {
  const tiles = document.querySelectorAll("#board img");
  tiles.forEach(tile => {
    tile.addEventListener("dragstart", this.dragStart.bind(this));
    tile.addEventListener("dragover", this.dragOver.bind(this));
    tile.addEventListener("dragenter", this.dragEnter.bind(this));
    tile.addEventListener("dragleave", this.dragLeave.bind(this));
    tile.addEventListener("drop", this.dragDrop.bind(this));
    tile.addEventListener("dragend", this.dragEnd.bind(this));
  });
}
  1. 修改puzzleStart,先填充棋盘再绑定事件:
puzzleStart() {
  this._randomizeOrder();
  this.populateBoard();
  this.assignEvents(); // 填充完成后绑定事件
}

事件方法的调整同方案一,用e.target获取对应tile元素。


额外优化点

_randomizeOrder中直接用sort修改原数组this.imageOrder,会导致后续调用时原数组已乱序,建议复制原数组再排序:

_randomizeOrder() {
  if (!this.imageOrder) return undefined;
  this.randomOrder = [...this.imageOrder].sort(() => Math.random() - 0.5);
  return this.randomOrder;
}

内容的提问来源于stack exchange,提问作者Jorge Mendez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 05:55:15