Jquery UI 未启用 Dragabble

Jquery UI Dragabble is not enabled

class Cell {
    
  constructor(game, index) {
    this.isEmpty = false;
    this.game = game;
    this.index = index;
    this.height = (game.height / game.dimension);
    this.width = (game.width / game.dimension);  
    this.id = "cell-" + index;
    this.cell = this.createCell();
    $("#content").append(this.cell);
    if (this.index === this.game.dimension * this.game.dimension - 1) {
      this.isEmpty = true;
      return;
    }
    this.setImage();
    this.setPosition(this.index)
  }
    
  createCell() {
    const cell = document.createElement("div");    
    $(cell).css({
      "width": this.height + "px",
      "height": this.width + "px",
      "position": "absolute",
      "border": "1px solid #fff"
    })
    $(cell).attr("id", this.id);
    //On click Move to the Empty Space
    $(cell).on("click", () => {
      if (this.game.gameStarted) {
        let validCells = this.game.checkValidCells();
        let compareCells = [];
        if (validCells.right) {
          compareCells.push(this.game.cells[validCells.right].cell);
        }
        if (validCells.left || validCells.left === 0) {
          compareCells.push(this.game.cells[validCells.left].cell);
        }
        if (validCells.top || validCells.top === 0) {
          compareCells.push(this.game.cells[validCells.top].cell);
        }
        if (validCells.bottom) {
          compareCells.push(this.game.cells[validCells.bottom].cell);
        }
        let i = this.game.cells.findIndex(item => item.cell === cell);
        let j = this.game.findEmptyCell();
        if (compareCells.indexOf(cell) != -1) {
          [this.game.cells[i], this.game.cells[j]] = [this.game.cells[j], this.game.cells[i]];  
          this.game.cells[i].setPosition(i);
          this.game.cells[j].setPosition(j);
          if (this.game.checkWin()) {
             alert("you won the game!!");
             this.game.numberOfMoves = 0; 
             this.game.gameStarted = false;
          }
          this.game.numberOfMoves++;
          $("#moves").html("Moves: " + this.game.numberOfMoves);
        }
        this.game.dragTheTile();
      }
    })
    return cell;
  }
    
  setImage() {
    const left = this.width * (this.index % this.game.dimension);
    const top = this.height * Math.floor(this.index / this.game.dimension);
    const bgPosition = -left + "px" + " " + -top + "px";
    const bgSize = this.game.width + "px " + this.game.height + "px" 
    $(this.cell).css({
      "background": 'url(' + this.game.imageSrc + ')',
      "background-position" : bgPosition,
      "background-size": bgSize
    })      
  }
    
  setPosition(index) {
    const {left, top} = this.getPosition(index);
    $(this.cell).css({
      "left": left + "px",
      "top": top + "px"
    })
  }
  
  makeDraggable(index) {
    let emptyCellIndex = this.game.findEmptyCell();
    $(this.cell).draggable({
      containment: "parent",
      snap: this.game.cells[emptyCellIndex],
      cursor: "move",
      snapMode: "inner",
      snapTolerance: 20,
      helper: "clone",
      opacity: 0.5
    })
  }
    
  makeDroppable(index) {
    $(this.cell).droppable({
      drop: (event, ui) => {
        let draggedCell;
        draggedCell = ui.draggable;
        let i = this.game.cells.findIndex(item => item.cell === draggedCell[0]);
        let j = this.game.findEmptyCell();
        [this.game.cells[i], this.game.cells[j]] = [this.game.cells[j], this.game.cells[i]];  
        this.game.cells[i].setPosition(i);
        this.game.cells[j].setPosition(j);
        this.game.clearDrag();
        this.game.numberOfMoves++;
        $("#moves").html("Moves: " + this.game.numberOfMoves);
        if (this.game.checkWin()) {
          alert("you won the game!!");
          this.game.numberOfMoves = 0;
          this.game.gameStarted = false;
        } else {
          this.game.dragTheTile();
        }
      }
    })
  }
 
  getPosition(index) {
    return {
      left: this.width * (index % this.game.dimension),
      top: this.height * Math.floor(index / this.game.dimension)
    }
  }
    
}
class GameBoard {
  constructor(dimension){
    this.dimension = dimension;
    this.imageSrc = 'https://i.ibb.co/1XfXq6S/image.jpg'
    this.cells = [];
    let length = Math.min(window.innerHeight, window.innerWidth);
    this.width = length - 100;
    this.height = length - 100;
    this.setup();
    this.gameStarted = false;
    this.numberOfMoves = 0;
  }
 
  setup() {
    for(let i = 0;i < this.dimension * this.dimension; i++) {
      this.cells.push(new Cell(this, i));
    }
  }

  shuffle() {
    for (let i = this.cells.length -1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [this.cells[i], this.cells[j]] = [this.cells[j], this.cells[i]];  
      this.cells[i].setPosition(i);
      this.cells[j].setPosition(j);
    }
  }
    
  findEmptyCell() {
    return this.cells.findIndex(cell => cell.isEmpty)
  }
    
  checkValidCells() {
    const emptyCell = this.findEmptyCell(),
    topCell = emptyCell - this.dimension,
    leftCell = emptyCell - 1,
    rightCell = emptyCell + 1,
    bottomCell = emptyCell + this.dimension;
    const mod = emptyCell % this.dimension;
    let left, right, top, bottom;
    if (mod != 0) {
      left = leftCell;
    } 
    if (mod != this.dimension -1) {
      right = rightCell;
    }
    if (emptyCell >= this.dimension) {
      top = topCell;
    }
    if (emptyCell < this.dimension * (this.dimension - 1)) {
      bottom = bottomCell
    }
    return {right: right, left: left, top: top, bottom: bottom};
  }

  findPosition(index) {
    return this.cells.findIndex(cell => cell.index === index);
  }
    
  checkWin() {
    for (let i = 0; i < this.cells.length; i++) {
      if (i != this.cells[i].index) {
        return false;
      }
    }
    return true;
  }

  clearDrag() {
    this.cells.forEach(cell => {  
      if($(cell.cell).data('ui-draggable')) $(cell.cell).draggable("destroy");
    })
  }

  dragTheTile() {
    this.clearDrag();
    const validCells = this.checkValidCells();
    let availableCells = [];
    if (validCells.right) {
      availableCells.push(this.cells[this.findPosition(validCells.right)].index);
    }
    if (validCells.left || validCells.left === 0) {
      availableCells.push(this.cells[this.findPosition(validCells.left)].index);
    }
    if (validCells.top || validCells.top === 0) {
      availableCells.push(this.cells[this.findPosition(validCells.top)].index);  
    }
    if (validCells.bottom) {
      availableCells.push(this.cells[this.findPosition(validCells.bottom)].index);   
    }
    let emptyCellIndex = this.findEmptyCell();
    availableCells.forEach(cell => {
      this.cells[cell].makeDraggable(cell);
      this.cells[emptyCellIndex].makeDroppable(cell);
    })
  }

  solve() {
    let i;
    for (i = 0; i < this.cells.length; i++) {
      let j = this.cells[i].index;
      if (i != j) {
        [this.cells[i], this.cells[j]] = [this.cells[j], this.cells[i]];  
        this.cells[i].setPosition(i);
        this.cells[j].setPosition(j);
        i--;
      }
      if (i === this.cells.length - 1) {
        [this.cells[i], this.cells[i - 1]] = [this.cells[i - 1], this.cells[i]];  
        this.cells[i].setPosition(i);
        this.cells[i - 1].setPosition(i - 1);
      }
    }
  }
    
}
$(document).ready(() => {
  let gb;
  $("#startGame").on("click", () => {
    gb.gameStarted = true;
    gb.shuffle();
    gb.numberOfMoves = 0;
    $("#moves").html("Moves: " + gb.numberOfMoves);
    gb.clearDrag();
    gb.dragTheTile();
  })
  $("#solve").on("click", () => {
    if (gb.gameStarted) {
      gb.solve();
      gb.clearDrag();
      gb.dragTheTile();
    }
  })
  $("#generate-puzzle").on("click", () => {
    let number = parseInt($("#dimension").val());
    if(number >= 3 && Number.isInteger(number)) {
      gb = new GameBoard(number);
      $("#content").css("display", "block");
      $("#solve").css("display", "block");
      $("#startGame").css("display", "block");
      $("#enter-dimension").css("display", "none");
      $("#content").css({
        width: gb.width + "px",
        height : gb.height + "px"
      })
    } else {
      $("#alert").css("display", "block");
    }
  })
})
body {
    background-color: #3d3d3d;
}

#content {
  width: 400px;
  height : 400px;
  background-color: #fff;
  margin:  auto;
  position: relative;
  display: none;
}
#startGame {
  margin: auto;
  display: none;
}
#solve {
  margin: auto;
  display: none;
}
#alert {
  display: none;
}
#moves {
  margin: auto;
  padding:  5px;
  text-align: center;
  color: #FFFF00;

}
#enter-dimension {
  margin: auto; 
}
#label-dimension {
  color: #ddd;
}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <!-- JQuery -->
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

     <!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous"></script>

  <title>Image Puzzle</title>
      
</head>
    
<body>
  
  <div class="container col-md-6">
    <div id="moves">
    Moves : 0
    </div>
    <div class="d-flex justify-content-center row">
      <div class="col-md-6">
        <div class="mt-5" id="enter-dimension">
        <form>
        <div class="form-group">
          <label id="label-dimension" for="dimension">Enter the Dimension of the puzzle</label>
          <input type="number" class="form-control" id="dimension">
        </div>
        <div class="alert alert-danger" id="alert" role="alert">
         Enter a Valid Positive Integer Greater than or Equal to 3
        </div>
        <button type="button" class="btn btn-primary" id="generate-puzzle">Generate the Puzzle</button>
        </form>
        </div>
      </div>
    </div>
    <div class="row">
         <!--The GRid Layout and the tiles -->
      <div class="mt-3"  id="content">
      </div>
    </div>
    <!--Button to Start the Game -->
    <div class="row buttons">
      <button type="button" class="btn btn-info mt-2" id="startGame">Start Game</button>
      <button type="button" class="btn btn-success mt-2" id="solve">Solve This!</button>
    </div>   
  </div>
      
</body>
    
</html>

拼图完美,但有一个问题。如果我将一个单元格拖放到一个空单元格中,我将无法将该图块再次拖放到它之前的位置,即当前的空单元格。在我看来,makeDraggable() 和 dragTheTile() 函数中某处存在问题。 当我用鼠标单击移动一个单元格时,我可以将同一个单元格拖放到它以前的位置(这是当前的空单元格)或者如果我将一个单元格拖放到一个空的 space 我可以将它移动到通过鼠标单击它的先前位置(这是当前的空单元格)。但是拖动同一个单元格后不能再次拖动。看起来 draggable() 对那个特定的单元格是禁用的。 一旦一个单元格被拖动,下一步它应该是一个可拖动的单元格(因为它是空单元格的相邻单元格)当我让它可拖动时“ui-draggable”class 添加到其中,但缺少“ui-draggable-handle”class。

问题出在我清除可拖动对象的函数 属性:

clearDrag() {
    this.cells.forEach(cell => {  
      if($(cell.cell).data('ui-draggable')) $(cell.cell).draggable("destroy");
    })
  }

“destroy”方法给出了一些冲突。 我发现的另一种方法是首先使用 draggable 属性 初始化所有单元格,但在开始时禁用它并在需要时再次启用它。 这里使用的属性是“disabled: true”和“disabled: false”。

我编写了一个名为 dragTile() 的新函数,而不是 dragTheTile() 函数,如下所示:

 dragTile() {
    this.cells.forEach(cell => {
      cell.makeDraggable();
    })
    const validCells = this.checkValidCells();
    let availableCells = [];
    if (validCells.right) {
      availableCells.push(this.cells[this.findPosition(validCells.right)].index);
    }
    if (validCells.left || validCells.left === 0) {
      availableCells.push(this.cells[this.findPosition(validCells.left)].index);
    }
    if (validCells.top || validCells.top === 0) {
      availableCells.push(this.cells[this.findPosition(validCells.top)].index);  
    }
    if (validCells.bottom) {
      availableCells.push(this.cells[this.findPosition(validCells.bottom)].index);   
    }
    let emptyCellIndex = this.findEmptyCell();
    availableCells.forEach(cell => {
      $(this.cells[cell].cell).draggable({disabled: false});
    })
    this.cells[emptyCellIndex].makeDroppable(availableCells);
  }


这很容易解决问题。