手把手教你用 HTML+CSS+JS 写一个能玩的简易象棋!(附完整源码)

485 阅读3分钟

有没有想过,不用框架、不靠第三方库,只用最基础的 HTML + CSS + JS,写出一个可以点、可以走、还能悔棋的中国象棋小游戏?

今天,带你一步步从 0 开始,搭建一个能玩的网页版象棋!🌟
最后还有完整源码,直接拿来练手、改造!


🧠 项目功能预览

  • • 绘制标准9×10象棋棋盘
  • • 棋子初始排布
  • • 支持点击选子、点击落子
  • • 支持吃子(不能吃自己人)
  • • 简单胜负判定(帅/将被吃掉)
  • • 支持悔棋重新开始
  • • 不依赖任何库,纯原生实现

🎨 页面结构 (index.html)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>简易象棋</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>简易象棋</h1>

  <div id="controls">
    <button onclick="restartGame()">重新开始</button>
    <button onclick="undoMove()">悔棋</button>
  </div>

  <div id="chessboard"></div>

  <script src="script.js"></script>
</body>
</html>

结构非常简单,主体分为:标题、控制按钮区、棋盘区域。


🎨 样式美化 (style.css)

body {
  font-family: Arial, sans-serif;
  text-align: center;
  background#f5f5dc;
}

h1 {
  margin-top20px;
}

#controls {
  margin-bottom10px;
}

#chessboard {
  width450px;
  height500px;
  margin0 auto;
  display: grid;
  grid-template-columnsrepeat(91fr);
  grid-template-rowsrepeat(101fr);
  border2px solid #333;
  background#ffe4c4;
  position: relative;
}

.cell {
  border1px solid #333;
  position: relative;
}

.piece {
  width90%;
  height90%;
  margin5%;
  border-radius50%;
  background#d9b382;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size18px;
  cursor: pointer;
  user-select: none;
}

.red {
  color: red;
}

.black {
  color: black;
}

让棋盘有格子,有背景,棋子圆圆胖胖,看着更舒服。


🧩 核心逻辑 (script.js)

const board = document.getElementById('chessboard');
let selectedPiece = null;
let selectedCell = null;
let moveHistory = [];

const initialPieces = {
  "0,0": { text"车"color"black" },
  "1,0": { text"马"color"black" },
  "2,0": { text"象"color"black" },
  "3,0": { text"士"color"black" },
  "4,0": { text"将"color"black" },
  "5,0": { text"士"color"black" },
  "6,0": { text"象"color"black" },
  "7,0": { text"马"color"black" },
  "8,0": { text"车"color"black" },
  "1,2": { text"炮"color"black" },
  "7,2": { text"炮"color"black" },
  "0,3": { text"兵"color"black" },
  "2,3": { text"兵"color"black" },
  "4,3": { text"兵"color"black" },
  "6,3": { text"兵"color"black" },
  "8,3": { text"兵"color"black" },

  "0,9": { text"车"color"red" },
  "1,9": { text"马"color"red" },
  "2,9": { text"相"color"red" },
  "3,9": { text"仕"color"red" },
  "4,9": { text"帅"color"red" },
  "5,9": { text"仕"color"red" },
  "6,9": { text"相"color"red" },
  "7,9": { text"马"color"red" },
  "8,9": { text"车"color"red" },
  "1,7": { text"炮"color"red" },
  "7,7": { text"炮"color"red" },
  "0,6": { text"兵"color"red" },
  "2,6": { text"兵"color"red" },
  "4,6": { text"兵"color"red" },
  "6,6": { text"兵"color"red" },
  "8,6": { text"兵"color"red" },
};

function createBoard() {
  board.innerHTML = '';
  for (let y = 0; y < 10; y++) {
    for (let x = 0; x < 9; x++) {
      const cell = document.createElement('div');
      cell.className = 'cell';
      cell.dataset.x = x;
      cell.dataset.y = y;

      const key = `${x},${y}`;
      if (initialPieces[key]) {
        const piece = document.createElement('div');
        piece.className = `piece ${initialPieces[key].color}`;
        piece.innerText = initialPieces[key].text;
        cell.appendChild(piece);
      }

      cell.addEventListener('click', onCellClick);
      board.appendChild(cell);
    }
  }
}

function onCellClick(e) {
  const cell = e.currentTarget;
  const piece = cell.querySelector('.piece');

  if (selectedPiece) {
    if (!piece || selectedPiece.classList.contains('red') !== piece.classList.contains('red')) {
      moveHistory.push({
        fromX: selectedCell.dataset.x,
        fromY: selectedCell.dataset.y,
        toX: cell.dataset.x,
        toY: cell.dataset.y,
        movedPiece: selectedPiece,
        capturedPiece: piece
      });

      if (piece) {
        piece.remove();
      }

      cell.appendChild(selectedPiece);
      selectedPiece.style.border = "none";

      if (piece && (piece.innerText === "帅" || piece.innerText === "将")) {
        alert((piece.classList.contains('red') ? "黑方胜利!" : "红方胜利!"));
        restartGame();
        return;
      }
    } else {
      alert("不能吃自己人!");
    }
    selectedPiece = null;
    selectedCell = null;
  } else if (piece) {
    selectedPiece = piece;
    selectedCell = cell;
    piece.style.border = "2px solid blue";
  }
}

function restartGame() {
  selectedPiece = null;
  selectedCell = null;
  moveHistory = [];
  createBoard();
}

function undoMove() {
  if (moveHistory.length === 0) {
    alert("没有可以悔棋的步骤!");
    return;
  }

  const lastMove = moveHistory.pop();
  const fromCell = getCell(lastMove.fromX, lastMove.fromY);
  const toCell = getCell(lastMove.toX, lastMove.toY);

  fromCell.appendChild(lastMove.movedPiece);

  if (lastMove.capturedPiece) {
    toCell.appendChild(lastMove.capturedPiece);
  }
}

function getCell(x, y) {
  return document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
}

createBoard();

🎯 总结

虽然这个象棋项目比较基础:

  • • 还没加上复杂走法规则(比如马走日、炮隔子)
  • • 红黑轮流行棋目前也没有加
  • • 动画、提示、保存进度还没做

作为前端练习小项目完美够用

👉 想要继续升级?可以考虑:

  • • 添加走法验证(每种棋子不同)
  • • 支持双人对战模式
  • • 支持手机触控
  • • 自动保存棋局进度
  • • 带AI简单对弈

🔵 源码已给,赶紧动手试试看吧!
🔵 如果你想要升级版功能,可以留言告诉我,一起继续完善它!