You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建可点击交点的响应式Gomoku(五子棋)棋盘

五子棋棋盘适配与简化实现方案

问题1:让网格在所有屏幕尺寸下正常显示(最小宽度275px)

核心思路是强制棋盘容器保持正方形比例,同时限制宽高范围,再用Grid布局均分单元格:

  1. 给棋盘父容器设置基础样式

    .gomoku-board {
      /* 限制宽度范围 */
      min-width: 275px;
      max-width: 90vw; /* 大屏幕下不撑满,留边距 */
      /* 强制正方形 */
      aspect-ratio: 1 / 1;
      margin: 0 auto; /* 水平居中 */
      /* Grid布局均分单元格 */
      display: grid;
      grid-template-columns: repeat(15, 1fr); /* 15路棋盘,按需修改路数 */
      grid-template-rows: repeat(15, 1fr);
      position: relative;
      padding: 0;
      border: 2px solid #333; /* 棋盘外框 */
    }
    
  2. 单元格(点击区域)样式
    单元格只需要作为点击容器,交点和棋盘线用父容器伪元素实现,避免DOM冗余:

    .cell {
      position: relative;
      cursor: pointer;
    }
    
  3. 用伪元素绘制棋盘网格线(替代单元格边框,避免重复线条)

    .gomoku-board::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      /* 生成横竖网格线 */
      background-image: 
        linear-gradient(to right, #333 1px, transparent 1px),
        linear-gradient(to bottom, #333 1px, transparent 1px);
      /* 线间距:15路棋盘的话,是总宽高除以14(间隔数) */
      background-size: calc(100% / 14) calc(100% / 14);
      background-position: center;
      pointer-events: none; /* 不干扰单元格点击 */
    }
    
  4. 点击后显示棋子(Vue中通过绑定数据控制)
    比如给单元格添加v-if显示棋子:

    <div class="cell" @click="handleClick(row, col)">
      <div class="piece" v-if="board[row][col]" :class="board[row][col]"></div>
    </div>
    

    棋子样式:

    .piece {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 70%;
      height: 70%;
      border-radius: 50%;
    }
    .piece.black { background-color: #000; }
    .piece.white { background-color: #fff; border: 1px solid #000; }
    

这样设置后,棋盘会自动适配屏幕:大屏幕下最多占90%宽度,小屏幕下保持275px宽,始终是正方形,单元格也会跟着等比例缩放。


问题2:更简单的实现方案

推荐用Canvas绘制棋盘,DOM结构极简,适配更轻松,性能也更好(尤其多路数棋盘):

  1. Vue中定义Canvas元素

    <canvas ref="gomokuCanvas" @click="handleCanvasClick"></canvas>
    
  2. Canvas样式设置(同样保持正方形比例)

    canvas {
      min-width: 275px;
      max-width: 90vw;
      aspect-ratio: 1 / 1;
      display: block;
      margin: 0 auto;
      border: 2px solid #333;
    }
    
  3. 初始化绘制棋盘
    在Vue的mounted钩子中获取Canvas上下文,绘制网格线:

    const canvas = this.$refs.gomokuCanvas;
    const ctx = canvas.getContext('2d');
    // 设置Canvas实际分辨率(避免模糊)
    const size = Math.max(canvas.offsetWidth, 275);
    canvas.width = size;
    canvas.height = size;
    const gridCount = 15; // 15路棋盘
    const gridSize = size / (gridCount - 1);
    
    // 绘制网格线
    ctx.strokeStyle = '#333';
    ctx.lineWidth = 1;
    for (let i = 0; i < gridCount; i++) {
      // 横线
      ctx.beginPath();
      ctx.moveTo(0, i * gridSize);
      ctx.lineTo(size, i * gridSize);
      ctx.stroke();
      // 竖线
      ctx.beginPath();
      ctx.moveTo(i * gridSize, 0);
      ctx.lineTo(i * gridSize, size);
      ctx.stroke();
    }
    
  4. 处理点击事件,计算交点并绘制棋子

    handleCanvasClick(e) {
      const canvas = this.$refs.gomokuCanvas;
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      const gridSize = canvas.width / 14; // 15路的间隔
      // 计算最近的网格交点
      const col = Math.round(x / gridSize);
      const row = Math.round(y / gridSize);
      // 绘制棋子
      const ctx = canvas.getContext('2d');
      ctx.beginPath();
      ctx.arc(col * gridSize, row * gridSize, gridSize * 0.35, 0, Math.PI * 2);
      ctx.fillStyle = this.currentPlayer === 'black' ? '#000' : '#fff';
      ctx.fill();
      ctx.strokeStyle = '#000';
      ctx.stroke();
      // 切换玩家等逻辑...
    }
    

这种方案不需要生成大量的单元格DOM,只用一个Canvas就能完成棋盘绘制和交互,适配逻辑更简单,代码量也更少。


内容的提问来源于stack exchange,提问作者eligolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:25:18