有没有办法获得视觉上位于某个元素下方或上方或左侧或右侧的元素?

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

我正在与 JavaScript
一起开发简单游戏(经典数字游戏) 其中带有显示 Flex 的容器 div 包含 9 divs
8 div 是蓝色的,里面有数字从 1 到 8 和 1 div 是白色的,没有任何内容
每次加载页面时,div 都会随机排序
image of the game
并且空 div 也是随机放置的。

任务是重新排列从 1 到 8 的数字,当您单击任何 div 视觉上相邻的(上方、下方、左侧或右侧)时
到空 div
他们正在调换位置
在此图像中,允许移动的 div 是 4,7,5
我如何使用 javaScript 或 jquery 来实现?

这是我的代码:

$(document).ready(function(){
  var arr = [];
  
  for(i=1;i<9;i++)
  {
    arr.push(i);
  }
  
  arr.push("");

  function shuffleArray(array) 
  {
    for (let i = array.length - 1; i > 0; i--) 
    {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
  }
  
  shuffleArray(arr);

  for(i=0;i<9;i++)
  {
    divContent.innerHTML += "<div class='tile'>"+arr[i]+"</div>"
  }

  var tile = document.getElementsByClassName("tile");

  var n = 0;

  while (n < tile.length) 
  {
    if (tile[n].textContent != (n+1))
      break;
    
    tile[n].style.color = "yellow";
    n++;
  }

  for(i=0;i<tile.length;i++)
  {
    if(!tile[i].textContent)
    {
      tile[i].style.backgroundColor  = "#fff";
      tile[i].classList.add("whitt");
    }
    tile[i].style.color = "#fff";
  }

  $('.tile').click(function (evt) {
    var $div = $(evt.target).closest('.tile');
    $div.next('.tile').after($div).animate({opacity: 0.9, top:'100'}, 500 );

    for(i=0;i<tile.length;i++)
    {
      if(!tile[i].textContent)
      {
        tile[i].style.backgroundColor  = "#fff";
        tile[i].classList.add("whitt");
      }
      tile[i].style.color = "#fff";
    }

    n = 0;
    
    while (n < tile.length) 
    {
      tile[n].style.color = "#fff";
      if (tile[n].textContent != (n+1)) 
        break;
      tile[n].style.color = "yellow";
      n++;
    }
  });
});
.flexDiv{
  display:flex;
  flex-wrap: wrap;
  width:310px;
  border:1px solid black;
}
.tile{
  position:relative;
  background:#08088A;
  text-align:center;
  width:29%;
  margin:1px;
  font-size:75px;
  font-weight:bold;
  color:#fff;
  padding:5px;
}
.wh{
  background:#fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<div id="divContent" class="flexDiv"></div>

我个人使用 ::before 和 ::after CSS 选择器在给定元素前后添加 textContent。请查看 w3schools CSS 参考。

你有一些非常酷的动画。我作弊了,只是通过克隆交换了两个 DOM 元素,所以我认为我无法为它制作动画。我也没有尝试做任何聪明的事情来说明瓷砖可以移动到哪里。我只是做了一系列可能的动作,每次点击一个图块时,我都会得到一个可能的动作列表,我会检查每一个动作,看看它是否是空方块。如果是,交换瓷砖。

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;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" />
<div id="board"></div>