本页目录 技术实现思路

技术实现思路

Vue 3 + TypeScript 作为前端主框架具有以下优势: 1. 响应式系统改进:Vue 3 的 Composition API 提供了更灵活的状态管理方式,特别适合复杂的 Ban/Pick 状态机管理 2. 类型安全:TypeScript 提供强类型支持,减少运行时错误,特别适合团队协作开发 3. 移动端适配:Vue 3 的响应式特性可以很好地适配...

技术栈推荐

前端技术栈

主框架选择

Vue 3 + TypeScript 作为前端主框架具有以下优势:

  1. 响应式系统改进:Vue 3 的 Composition API 提供了更灵活的状态管理方式,特别适合复杂的 Ban/Pick 状态机管理
  2. 类型安全:TypeScript 提供强类型支持,减少运行时错误,特别适合团队协作开发
  3. 移动端适配:Vue 3 的响应式特性可以很好地适配不同屏幕尺寸,配合 CSS 媒体查询实现响应式布局
  4. 生态丰富:Vue 生态系统中有大量现成的动画库(如 Vue2-animate)、UI 组件库(如 Element Plus Mobile)

React 也是一个不错的选择,但考虑到项目需要快速开发和维护,Vue 3 的学习曲线相对平缓,社区中文资源更丰富。在移动端方面,React Native 可能不如 Vue 配合 Vite 构建的 H5 应用来得轻量。

推荐:Vue 3 + TypeScript

状态管理

Pinia + Composables 组合作为状态管理方案:

  1. Pinia:Vue 官方推荐的状态管理库,比 Vuex 更轻量、更易于理解,支持 TypeScript,提供了更好的 DevTools 集成
  2. Composables:Vue 3 的组合式函数,可以将 Ban/Pick 相关的状态逻辑封装为可复用的函数,提高代码复用性

具体的状态管理设计包括:

  • 房间状态:管理房间信息、用户身份、连接状态
  • 选人状态:管理当前阶段、剩余时间、已选球员、已 Ban 球员
  • UI 状态:管理界面显示、动画效果、倒计时等

推荐:Pinia + Composables

动画实现

Framer Motion 或 GSAP 配合 CSS 动画:

  1. Framer Motion:功能强大的动画库,支持手势操作、物理动画,API 直观易用
  2. GSAP:专业的动画库,性能优异,适合复杂的动画序列

对于 Ban/Pick 系统的动画需求,建议使用 GSAP 处理复杂的界面切换动画,CSS 动画处理简单的交互反馈,使用 Lottie 处理复杂的矢量动画(如倒计时效果)。

推荐:GSAP + CSS 动画

WebSocket 客户端

Socket.IO 客户端:

  1. 支持自动重连和心跳机制
  2. 提供房间广播功能,方便选人状态同步
  3. 支持命名空间和房间隔离
  4. 有完善的错误处理和降级机制

推荐:Socket.IO 客户端

构建工具

Vite:

  1. 开发环境启动速度快,热更新性能好
  2. 对 TypeScript、CSS 预处理器支持完善
  3. 拆包和代码优化能力强,适合 H5 应用
  4. 生态活跃,插件丰富

推荐:Vite

后端技术栈

主框架选择

Node.js + Express 或 NestJS:

  1. Node.js + Express:轻量、灵活,适合小型到中型项目,开发效率高
  2. NestJS:基于 Express 的企业级框架,提供了更好的代码组织和架构模式,适合大型项目

考虑到项目的实时性要求,推荐使用 NestJS,它内置了 WebSocket 支持,提供了更好的 TypeScript 支持和依赖注入机制,便于后续功能扩展。

推荐:NestJS

WebSocket 服务

Socket.IO 服务端:

  1. 与客户端保持一致,便于开发和维护
  2. 提供强大的房间管理和广播功能
  3. 支持中间件和认证机制
  4. 有完善的文档和社区支持

推荐:Socket.IO 服务端

数据存储

Redis + 内存存储:

  1. Redis:用于缓存频繁访问的数据(如球员信息)、存储房间状态
  2. 内存存储:用于选人过程中的临时数据存储,配合定时持久化到 Redis

考虑到项目不需要长期存储历史数据,可以优先使用内存存储,Redis 作为持久化和缓存层。

推荐:Redis + 内存存储

关键技术难点

并发控制与状态同步

问题背景

Ban/Pick 系统的核心挑战在于处理两个用户的同时操作。在网络延迟、用户快速操作的情况下,可能出现以下问题:

  1. 操作冲突:双方同时选择同一个球员
  2. 状态不一致:网络延迟导致一方看不到另一方的操作
  3. 超时处理:服务器端倒计时和客户端倒计时的同步问题

解决方案

乐观锁 + 版本控制:

  1. 每个房间维护一个版本号(version)
  2. 每个选人操作都携带当前版本号
  3. 服务端验证版本号,如果版本不一致则拒绝操作
  4. 客户端在收到版本冲突时,重新获取最新状态并更新界面

事件溯源模式:

  1. 所有选人操作作为事件存储
  2. 按时间顺序回放事件来重建状态
  3. 保证状态重建的一致性

具体实现:

// 房间状态结构
interface RoomState {
  version: number;
  currentPlayer: 'home' | 'away';
  phase: 'ban' | 'pick' | 'confirm';
  homePlayers: Player[];
  awayPlayers: Player[];
  bannedPlayers: Player[];
  lastActionTime: number;
}

// 操作消息
interface PickMessage {
  playerId: string;
  roomVersion: number; // 操作时的版本号
  timestamp: number;
}

// 服务端验证
async function handlePick(message: PickMessage) {
  const room = getRoom(message.roomId);
  if (room.version !== message.roomVersion) {
    return { status: 'conflict', currentVersion: room.version };
  }
  
  // 验证操作合法性
  if (room.currentPlayer !== 'home') {
    return { status: 'invalid', reason: 'not_your_turn' };
  }
  
  // 执行操作
  const player = room.availablePlayers.find(p => p.id === message.playerId);
  if (!player) {
    return { status: 'invalid', reason: 'player_not_available' };
  }
  
  // 更新状态
  room.homePlayers.push(player);
  room.availablePlayers = room.availablePlayers.filter(p => p.id !== message.playerId);
  room.version++;
  
  // 广播更新
  broadcastRoomUpdate(room);
}

倒计时同步

服务器主导的倒计时:

  1. 倒计时由服务器控制,客户端只显示
  2. 服务器定期广播剩余时间
  3. 客户端收到时间更新后更新本地显示
  4. 网络延迟造成的误差可以通过时间校准解决

心跳检测:

  1. 客户端定期向服务器发送心跳包
  2. 服务器检测到用户长时间无响应时,可以主动结束其回合
  3. 处理网络异常情况下的状态恢复

网络异常处理

问题背景

移动网络环境下,用户可能遇到:

  1. 网络切换(WiFi 到 4G)
  2. 信号波动
  3. 应用被系统挂起
  4. 网络完全断开

解决方案

智能重连机制:

  1. 断网检测:客户端定期检测连接状态
  2. 渐进式重连:1s、2s、4s、8s 的指数退避算法
  3. 连接恢复后:同步最新状态,补发丢失的操作
  4. 超时处理:长时间无响应,可提醒用户重新连接

状态缓存:

  1. 客户端缓存关键状态(当前房间、选人进度)
  2. 重连后从服务器获取最新状态,比对并同步本地状态
  3. 对于已完成的部分操作,避免重复执行

离线标记:

  1. 当检测到用户离线时,界面显示离线状态
  2. 允许其他用户继续操作
  3. 用户重新上线后,状态自动同步

性能优化

图片加载优化

懒加载 + 预加载:

  1. 球员图片使用懒加载,只加载当前视图的球员
  2. 对于即将显示的球员(如下一批),进行预加载
  3. 图片格式使用 WebP 或 AVIF,减少文件大小
  4. 实现图片缓存策略,避免重复下载

渐进式加载:

  1. 先显示低分辨率图片占位
  2. 再加载高分辨率完整图片
  3. 使用模糊效果过渡,提升用户体验

WebSocket 性能优化

消息压缩:

  1. 使用 JSON 压缩算法减少消息大小
  2. 对于频繁更新的状态(如倒计时),采用增量更新
  3. 合并多个状态更新为单次消息

连接管理:

  1. 单个 WebSocket 连接处理所有消息
  2. 使用房间频道隔离不同房间的消息
  3. 实现连接池管理,避免创建过多连接

动画性能优化

GPU 加速:

  1. 使用 transform 和 opacity 属性触发 GPU 加速
  2. 避免频繁修改 width、height、left、top 属性
  3. 使用 will-change 提示浏览器优化渲染

减少重排重绘:

  1. 使用 requestAnimationFrame 协调动画帧
  2. 复用 DOM 元素,避免频繁创建和销毁
  3. 使用 Canvas 绘制复杂动画,如能力值雷达图

架构设计

整体架构

采用微服务架构,但由于项目规模较小,建议采用模块化单体应用架构:

┌─────────────────┐    ┌─────────────────┐
│   H5 Client    │    │   Admin Client   │
│   (Vue 3)      │    │   (Vue 3)       │
└────────┬───────┘    └────────┬─────────┘
         │                    │
         ▼                    ▼
┌─────────────────────────────────────┐
│         WebSocket Server            │
│        (NestJS + Socket.IO)        │
│                                     │
│  ┌─────────────┐ ┌──────────────┐   │
│  │  Room Service │ │  Game Logic │   │
│  └─────────────┘ └──────────────┘   │
│                                     │
│  ┌─────────────┐ ┌──────────────┐   │
│  │   Redis     │ │   Data       │   │
│  │   Cache     │ │   Store      │   │
│  └─────────────┘ └──────────────┘   │
└─────────────────────────────────────┘

数据流设计

选人操作的数据流:

  1. 用户点击球员卡片
  2. 前端验证操作合法性(当前回合、球员可选)
  3. 发送 WebSocket 消息到服务器
  4. 服务器验证操作(版本检查、业务规则)
  5. 更新房间状态,广播更新消息
  6. 其他客户端收到更新,刷新界面
  7. 操作完成后,进入下一阶段或下一回合

状态同步的数据流:

  1. 服务器维护房间状态
  2. 定期广播状态更新(包含版本号)
  3. 客户端收到更新,比对版本号
  4. 版本不一致时,同步最新状态
  5. 客户端本地状态与服务器保持一致

部署方案

开发环境

本地开发:

  1. 使用 Docker Compose 快速搭建开发环境
  2. 前端使用 Vite 开发服务器,支持热更新
  3. 后端使用 NestJS 开发服务器,支持自动重启
  4. Redis 使用 Docker 容器

代码组织:

banpick-game/
├── frontend/         # Vue 3 前端项目
│   ├── src/
│   │   ├── components/  # 组件
│   │   ├── composables/ # 组合式函数
│   │   ├── stores/     # Pinia 状态管理
│   │   └── utils/      # 工具函数
├── backend/           # NestJS 后端项目
│   ├── src/
│   │   ├── modules/
│   │   │   ├── room/   # 房间模块
│   │   │   ├── game/   # 游戏逻辑模块
│   │   │   └── user/   # 用户模块
│   │   └── websockets/ # WebSocket 处理
├── data/              # 静态数据(球员信息等)
└── docker-compose.yml # 开发环境配置

生产环境

云原生部署:

  1. 使用 Docker 容器化部署
  2. Kubernetes 进行容器编排和自动扩缩容
  3. 使用 Nginx 作为反向代理,处理静态资源
  4. Redis 集群提供高可用缓存

CDN 加速:

  1. 球员图片和静态资源使用 CDN 加速
  2. WebSocket 连接直连应用服务器,避免代理延迟

监控日志:

  1. 使用 Prometheus + Grafana 监控系统状态
  2. ELK Stack 收集和分析日志
  3. 前端错误上报机制,及时发现和修复问题

安全考虑

数据安全

输入验证:

  1. 所有 WebSocket 消息都进行严格验证
  2. 防止 SQL 注入、XSS 攻击
  3. 验证操作的权限和合法性

敏感信息保护:

  1. 球员图片等资源使用临时链接,防止盗用
  2. 敏感操作需要二次确认
  3. 防止 CSRF 攻击

通信安全

HTTPS + WSS:

  1. 使用 HTTPS 加密 HTTP 请求
  2. 使用 WSS (WebSocket Secure) 加密 WebSocket 连接
  3. 实现证书管理和自动更新

参考资料