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

如何将战舰游戏HTML网格元素与JavaScript数组关联实现拖拽置船?

战舰游戏:拖拽船只同步网格数组实现方案

先搞定拖拽的基础配置

给每个可拖拽的船只DOM元素加上draggable="true",再用data-*属性存好船只的关键信息——比如长度data-length="3"、初始方向data-direction="horizontal"(水平/垂直)。然后监听dragstart事件,把这些信息存到拖拽数据里,顺便加个拖拽时的视觉反馈:

document.querySelectorAll('.ship').forEach(ship => {
  ship.draggable = true;
  ship.addEventListener('dragstart', (e) => {
    // 把船只数据转成JSON存在拖拽对象里
    e.dataTransfer.setData('text/plain', JSON.stringify({
      length: parseInt(ship.dataset.length),
      direction: ship.dataset.direction
    }));
    // 拖拽时给船只加个半透明样式,用户一眼能看出来
    ship.classList.add('dragging');
  });
  // 拖拽结束后移除样式
  ship.addEventListener('dragend', () => ship.classList.remove('dragging'));
});

处理网格的放置逻辑

首先给player1Board里的每个单元格(假设是.cell类)设置data-row和data-col属性,比如<div class="cell" data-row="0" data-col="0"></div>,这样能快速拿到单元格的行列坐标。

然后监听单元格的dragover事件,阻止默认行为才能允许放置,顺便加个hover的视觉提示:

document.querySelectorAll('#player1Board .cell').forEach(cell => {
  cell.addEventListener('dragover', (e) => {
    e.preventDefault();
    cell.classList.add('hovered');
  });
  cell.addEventListener('dragleave', () => cell.classList.remove('hovered'));
});

接下来是核心的drop事件处理——拿到拖拽的船只信息,计算它要占据的所有单元格,同步更新数组和DOM:

document.querySelector('#player1Board').addEventListener('drop', (e) => {
  e.preventDefault();
  const targetCell = e.target.closest('.cell'); // 防止点到单元格内部元素
  if(!targetCell) return;
  
  targetCell.classList.remove('hovered');
  // 取出之前存的船只数据
  const shipData = JSON.parse(e.dataTransfer.getData('text/plain'));
  const dropRow = parseInt(targetCell.dataset.row);
  const dropCol = parseInt(targetCell.dataset.col);
  
  // 根据方向计算船只占据的所有单元格坐标
  const shipCells = [];
  for(let i = 0; i < shipData.length; i++) {
    if(shipData.direction === 'horizontal') {
      shipCells.push({ row: dropRow, col: dropCol + i });
    } else {
      shipCells.push({ row: dropRow + i, col: dropCol });
    }
  }
  
  // 先检查放置是否合法:不超出网格,且没有重叠船只
  const gridSize = player1.grid.length;
  const isValid = shipCells.every(cell => {
    return cell.row >= 0 && cell.row < gridSize 
           && cell.col >= 0 && cell.col < gridSize
           && player1.grid[cell.row][cell.col] === 0; // 假设0代表空单元格,1代表有船
  });
  
  if(isValid) {
    // 同步更新数组和DOM
    shipCells.forEach(cell => {
      player1.grid[cell.row][cell.col] = 1; // 标记数组位置为有船
      // 给对应单元格加样式,显示船只
      const cellEl = document.querySelector(`#player1Board .cell[data-row="${cell.row}"][data-col="${cell.col}"]`);
      cellEl.classList.add('has-ship');
    });
  } else {
    // 提示用户放置无效
    alert('这个位置放不了船哦,换个地方试试!');
  }
});

额外优化建议

  • 加个方向切换:点击船只时切换data-direction的值,同时更新船只的样式(比如水平变垂直),让用户能调整放置方向
  • 拖拽预览:在dragover时,提前把船只将要占据的单元格高亮出来,用户更清楚放置效果
  • 支持重新拖拽:允许把已放置的船拖走,拖走时清空对应数组位置和DOM样式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:45:45