0
Follow
0
View

Is there a way to get the element that is visually underneath or above or left or right a certain element?

dy15145071020 注册会员
2023-01-25 17:42

Yours has some really cool animations. I cheated and just swap two DOM elements by cloning so I don't think I can animate it. I also didn't try to do anything clever to say where tiles can move. I just made an array of possible moves and every time a tile is clicked, I get a list of possible moves and I check each one to see if it's the empty square. If it is, swap the tiles.

window.addEventListener("DOMContentLoaded", () => {
  const tiles = [1, 2, 3, 4, 5, 6, 7, 8, null];
  const shuffle = arr => {
    for (let i = 0; i < arr.length; i++) {
      const j = Math.floor(Math.random() * arr.length);
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
  };
  shuffle(tiles);

  const getPositions = pos => [
    [1, 3],
    [0, 2, 4],
    [1, 5],
    [0, 4, 6],
    [1, 3, 5, 7],
    [2, 4, 8],
    [3, 7],
    [4, 6, 8],
    [5, 7]
  ][pos];

  const swap = (elA, elB) => {
    const cloneA = elA.cloneNode(true);
    const cloneB = elB.cloneNode(true);
    elB.parentNode.replaceChild(cloneA, elB);
    elA.parentNode.replaceChild(cloneB, elA);
    return cloneA;
  };

  const board = document.getElementById("board");

  const tileClick = event => {
    const p = Array.from(event.target.parentNode.children).indexOf(
      event.target
    );
    const positions = getPositions(p);
    const move = positions.reduce((p, c) => {
      const node = board.childNodes[c];
      if (node && node.dataset.name === "empty") p = c;
      return p;
    }, null);
    if (move !== null)
      swap(board.childNodes[p], board.childNodes[move]).addEventListener(
        "click",
        tileClick
      );
    // TODO: check for winning board
  };

  tiles.forEach((tile, idx) => {
    const tileEl = document.createElement("div");
    tileEl.classList.add("tile");
    tileEl.innerHTML = tile;
    tileEl.dataset.name = tile ? tile : "empty";
    board.appendChild(tileEl);
    tileEl.addEventListener("click", tileClick);
  });
});
#board {
  display: grid;
  padding: 10px;
  gap: 10px;
  grid-template-columns: repeat(3, 100px);
  box-sizing: border-box;
  height: 340px;
  width: 340px;
  border: 1px solid black;
  user-select: none;
}

.tile {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100px;
  width: 100px;
  font-size: xx-large;
  background-color: blue;
  color: white;
  cursor: pointer;
  user-select: none;
}

.tile:empty {
  background-color: white;
  cursor: unset;
}

dldwyq 注册会员
2023-01-25 17:42

I have personally used ::before and ::after CSS selectors to add textContent before and after given a element .Do check out the w3schools CSS reference.

About the Author

Question Info

Publish Time
2023-01-25 17:42
Update Time
2023-01-25 17:42