本文css使用tailwindcss
Tailwind CSS - 只需书写 HTML 代码,无需书写 CSS,即可快速构建美观的网站。 | TailwindCSS中文文档 | TailwindCSS中文网
规则:在一个(3 * 3)的大正方上被分成个8个(1 * 1)小正方形,剩下的一个是空的,每个小正方形可以移动到空的位置上,若旁边没有空的位置,则无法移动。
实现效果:
点击对应的小正方形,若小正方形四周有空白处,会向空白处移动。
正方形恢复1,2,3,4,5,6,7,8的顺序为过关。
代码中详细分析了实现过程
// 胜利时的正方形模样
const winArr = [[1, 2, 3], [4, 5, 6], [7, 8, 0]]
// 正方体的宽
const BLOCK_SIZE = 130
// 每个小正方体的颜色
const bgMap: Record<number, string> = {
1: 'bg-red-300',
2: 'bg-blue-300',
3: 'bg-green-300',
4: 'bg-yellow-300',
5: 'bg-purple-300',
6: 'bg-pink-300',
7: 'bg-orange-300',
8: 'bg-teal-300',
}
// 其中一个小正方体
function YiKuai({ v, currArr, setCurrArr }: { v: number, currArr: number[][], setCurrArr: Function }) {
// 遍历3 * 3的正方体查找数字v的横坐标,纵坐标。
function findCoor() {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (currArr[i][j] === v) {
return [i, j]
}
}
}
return [-1, -1]
}
// 点击事件,移动一个正方体,逻辑就是观察四周有没有空的位置,这里假设空的位置是 0
function moveBlock(i: number, j: number) {
// 对应四个方向分别是——右,左,下,上
for (let nxArr of [[0, 1], [0, -1], [1, 0], [-1, 0]]) {
let nx = i + nxArr[0]
let ny = j + nxArr[1]
// 如果没有越界,并且找到了0的位置
if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3 && currArr[nx][ny] === 0) {
let tmpArr = JSON.parse(JSON.stringify(currArr))
let tmp = tmpArr[i][j]
tmpArr[i][j] = tmpArr[nx][ny]
tmpArr[nx][ny] = tmp
setCurrArr(tmpArr)
return
}
}
}
const [x, y] = findCoor()
return (
/**
* 这里利用定位,把每个小正方形定位到左上角,再利用transform偏移小正方形的位置。
* |—— —— —— ——
* |—— *
* |
* |
* 上面*的位置的下标是(1,2),先竖着,再横着,对应CSS中的transform,水平移动应该看y,竖直移动应该看x。
*/
<div className={`absolute top-0 left-0 flex justify-center items-center text-base transition-all duration-300
font-bold cursor-pointer hover:shadow-black hover:shadow-inner w-[130px] h-[130px] ` + (v === 0 ? 'hidden' : '') + ' ' + bgMap[v]}
style={{ transform: `translate(${y * BLOCK_SIZE}px, ${x * BLOCK_SIZE}px)` }} onClick={() => moveBlock(x, y)}>
{v}
</div>
)
}
// 拼图组件
export default function Jigsaw() {
const [currArr, setCurrArr] = useState([[1, 2, 3], [4, 6, 8], [7, 5, 0]])
// currArr和winArr完全一致,游戏胜利!
const judgeWin = () => {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (currArr[i][j] !== winArr[i][j]) {
return false
}
}
}
return true
}
useEffect(() => {
setTimeout(() => {
if (judgeWin()) {
alert('You Win!')
}
}, 100);
}, [currArr])
return (
<div className="w-screen h-screen justify-center items-center flex">
<div className="w-[394px] h-[394px] border-black border-2 box-border bg-white relative">
{
[...currArr.reduce((pre, cur) => [...pre, ...cur], [])]
.map((v, i) =>
<YiKuai key={i} v={v} currArr={currArr} setCurrArr={setCurrArr} />
)
}
</div>
</div>
)
}