点击查看html编辑器说明文档

CSS Grid 随机洗牌edit icon

|
|
Fork(复制)
|
|
提交反馈
嵌入
设置
下载
HTML
格式化
支持Emmet,输入 p 后按 Tab键试试吧!
<head> ...
展开
</head>
<body>


<div class="container">
  
</div>
</body>
SCSS
格式化
body {
    width: 100vw;
    height: 100vh;
    margin: 0;
    padding: 0;
    display: grid;
    place-items: center;
}

.container {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    grid-template-rows: repeat(10, 1fr);
    column-gap: 5px;
    row-gap: 5px;
}

.container>div {
    width: 40px;
    height: 40px;
    border-radius: 2px;
    transition: 0.25s all linear;
    transform: translateX(0);
}

@for $i from 1 through 100 {
    .container>div:nth-child(#{$i}) {
        background-color: hsla(255/100 * $i, 90, 50, 1);
    }
}
JS
格式化
const gridLength = 10;
let emptyBoxIndex = gridLength * gridLength - 1;
let pIndex = -1;
const boxes = [];
const boxesMap = {};
const pos = [];
const speed = 300; // 速度调整,数值越小速度越快
const size = 40;
const gap = 5;

for (let x = 0; x < gridLength * gridLength - 1; x++) {
    const div = document.createElement("div");
    document.querySelector(".container").appendChild(div);
    boxes.push(div);
    boxesMap[x] = x;
    pos.push([0, 0]);
}

boxesMap[gridLength * gridLength] = null;
pos.push([0, 0]);

const move = (index, pos) => {
    boxes[index].style.transform = `translateX(${
    pos[0] * (size + gap)
  }px) translateY(${pos[1] * (size + gap)}px)`;
};

let start;
let steps = 0;
let accumulator = 0;

const walk = (timestamp) => {
    if (start === undefined) start = timestamp;
    accumulator += timestamp - start;

    if (accumulator > speed) {
        accumulator = 0;
        steps++;
        start = timestamp;

        // generate a lut?
        const adjacent = [];

        if (
            emptyBoxIndex > gridLength - 1 &&
            emptyBoxIndex - gridLength !== pIndex
        ) {
            // 不是第一行
            adjacent.push(emptyBoxIndex - gridLength);
        }
        if (
            emptyBoxIndex < gridLength * gridLength - gridLength &&
            emptyBoxIndex + gridLength !== pIndex
        ) {
            // 不是最后一行
            adjacent.push(emptyBoxIndex + gridLength);
        }
        if (emptyBoxIndex % gridLength !== 0 && emptyBoxIndex - 1 !== pIndex) {
            // 不是第一列
            adjacent.push(emptyBoxIndex - 1);
        }
        if (
            emptyBoxIndex % gridLength !== gridLength - 1 &&
            emptyBoxIndex + 1 !== pIndex
        ) {
            // 不是最后一列
            adjacent.push(emptyBoxIndex + 1);
        }

        const m = Math.floor(Math.random() * adjacent.length);
        const boxesMapIndexToMove = adjacent[m];

        pIndex = emptyBoxIndex;
        const pTile = boxesMap[boxesMapIndexToMove];
        boxesMap[boxesMapIndexToMove] = boxesMap[emptyBoxIndex];
        boxesMap[emptyBoxIndex] = pTile;

        switch (emptyBoxIndex - boxesMapIndexToMove) {
            case 1:
                pos[boxesMap[emptyBoxIndex]][0] += 1;
                break;
            case gridLength:
                pos[boxesMap[emptyBoxIndex]][1] += 1;
                break;
            case -gridLength:
                pos[boxesMap[emptyBoxIndex]][1] -= 1;
                break;
            case -1:
                pos[boxesMap[emptyBoxIndex]][0] -= 1;
                break;
        }

        move(boxesMap[emptyBoxIndex], pos[boxesMap[emptyBoxIndex]]);

        emptyBoxIndex = boxesMapIndexToMove;
    }

    if (steps < 5000) {
        window.requestAnimationFrame(walk);
    }
};

window.requestAnimationFrame(walk);
预览
控制台