海克斯大乱斗攻略网站 —— 从零开发到云服务器部署全记录

本文记录了这个英雄联盟海克斯大乱斗攻略网站的完整开发思路、代码结构,以及如何把它部署到自己的云服务器上。适合有一点前端基础、想了解 Next.js 全栈开发流程的同学阅读。


一、项目是什么

这是一个英雄联盟「海克斯大乱斗」模式的攻略网站,主要功能有三个页面:

  • 英雄图鉴:展示所有英雄,支持搜索和职业筛选,点击进入详情
  • 英雄详情:展示英雄技能、推荐海克斯强化
  • 海克斯强化:所有强化按强度(S/A/B/C)和稀有度筛选
  • 出装推荐:热门英雄的推荐出装路线和胜率

技术栈:

  • Next.js 16(React 19)
  • TypeScript
  • Tailwind CSS v4
  • Riot Data Dragon API(拳头官方免费数据接口)
  • pnpm 包管理器

二、项目结构一览

python 复制代码
lol-web/
├── src/
│   ├── app/                        # Next.js App Router 页面目录
│   │   ├── layout.tsx              # 全局布局(导航栏)
│   │   ├── page.tsx                # 首页:英雄图鉴
│   │   ├── globals.css             # 全局样式(主题色变量)
│   │   ├── augments/
│   │   │   └── page.tsx            # 海克斯强化页
│   │   ├── builds/
│   │   │   └── page.tsx            # 出装推荐页
│   │   └── champions/
│   │       └── [id]/
│   │           └── page.tsx        # 英雄详情页(动态路由)
│   ├── components/
│   │   └── ChampionGrid.tsx        # 英雄网格组件(含搜索/筛选)
│   └── lib/
│       ├── ddragon.ts              # Riot Data Dragon API 封装
│       └── augments.ts             # 海克斯强化静态数据
├── package.json
├── pnpm-lock.yaml
├── postcss.config.mjs
└── tsconfig.json

三、核心概念:Next.js App Router

Next.js 13 之后引入了 App Router,和以前的 Pages Router 最大的区别是:

  • src/app/ 目录下每个文件夹代表一个路由
  • 文件夹里的 page.tsx 就是这个路由的页面
  • 默认所有组件都是服务端组件 (Server Component),可以直接 async/await 请求数据
  • 需要用到 useStateonClick 等浏览器交互的组件,顶部加 "use client" 声明

这个项目里:

  • page.tsx(首页)、builds/page.tsxchampions/[id]/page.tsx 都是服务端组件,直接在服务器上请求 Riot API
  • ChampionGrid.tsxaugments/page.tsx 是客户端组件,因为需要搜索框输入和按钮筛选的交互状态

四、数据来源:Riot Data Dragon

所有英雄数据来自拳头官方提供的免费静态资源接口,叫 Data Dragon,不需要任何 API Key。

封装在 src/lib/ddragon.ts

ts 复制代码
const DDRAGON_BASE = "https://ddragon.leagueoflegends.com";

// 获取最新版本号(如 "15.8.1")
export async function getLatestVersion(): Promise<string> {
  const res = await fetch(`${DDRAGON_BASE}/api/versions.json`, {
    next: { revalidate: 86400 }, // Next.js 缓存,每天刷新一次
  });
  const versions = await res.json();
  return versions[0]; // 数组第一个就是最新版本
}

// 获取所有英雄列表(中文)
export async function getChampions() {
  const version = await getLatestVersion();
  const res = await fetch(
    `${DDRAGON_BASE}/cdn/${version}/data/zh_CN/champion.json`,
    { next: { revalidate: 86400 } }
  );
  const data = await res.json();
  return data.data; // 返回一个以英雄ID为key的对象
}

// 获取单个英雄详情(含技能、皮肤等)
export async function getChampionDetail(id: string) {
  const version = await getLatestVersion();
  const res = await fetch(
    `${DDRAGON_BASE}/cdn/${version}/data/zh_CN/champion/${id}.json`,
    { next: { revalidate: 86400 } }
  );
  const data = await res.json();
  return data.data[id];
}

next: { revalidate: 86400 } 是 Next.js 的**增量静态再生(ISR)**功能,意思是这个请求的结果会被缓存 24 小时,不会每次访问都重新请求 Riot 服务器,既快又省流量。

英雄图片的 URL 规则是:

ruby 复制代码
https://ddragon.leagueoflegends.com/cdn/{版本号}/img/champion/{图片文件名}

五、页面逐一解析

1. 全局布局 layout.tsx

这是整个网站的外壳,所有页面都会套在这里面。包含:

  • 顶部固定导航栏(sticky top-0
  • 三个导航链接:英雄 / 海克斯强化 / 出装推荐
  • {children} 是各页面内容的插槽

主题色用了英雄联盟风格的金色 #c89b3c 和深色背景 #0a0e1a

2. 首页 page.tsx + ChampionGrid.tsx

首页是服务端组件,启动时并行请求英雄列表和版本号:

ts 复制代码
const [champions, version] = await Promise.all([
  getChampions(),
  getLatestVersion(),
]);

Promise.all 并行请求,比串行快一倍。

然后把数据传给客户端组件 ChampionGrid,由它负责搜索和筛选的交互逻辑。

ChampionGrid 里用 useState 管理搜索词和当前选中的职业标签,用 .filter() 实时过滤英雄列表,完全在前端完成,不需要再请求服务器。

3. 英雄详情页 champions/[id]/page.tsx

[id] 是 Next.js 的动态路由 ,方括号表示这是一个变量。访问 /champions/Jinx 时,id 就是 "Jinx"

页面展示:

  • 英雄头像、名字、称号、职业标签
  • 被动技能 + Q/W/E/R 四个主动技能(图标 + 名称)
  • 推荐海克斯强化(从静态数据里取 S/A 级强化)

如果英雄 ID 不存在,调用 Next.js 内置的 notFound() 自动跳转 404 页面。

4. 海克斯强化页 augments/page.tsx

纯客户端组件,数据来自本地静态文件 src/lib/augments.ts(手动维护的强化数据)。

支持两个维度的筛选:

  • 强度等级:S / A / B / C
  • 稀有度:棱彩 / 金色 / 银色

每个强化卡片根据稀有度显示不同的背景色(紫色/黄色/灰色)。

5. 出装推荐页 builds/page.tsx

服务端组件,出装数据是硬编码在文件里的静态数组(模拟高胜率数据)。

同时请求英雄列表来获取英雄头像,展示每个英雄的推荐出装顺序和推荐强化组合。


六、样式方案:Tailwind CSS v4

项目用的是 Tailwind CSS v4,和 v3 的主要区别是配置方式变了:

  • 不再需要 tailwind.config.js
  • 直接在 globals.css 里用 @import "tailwindcss" 引入
  • CSS 变量直接在 :root 里定义
css 复制代码
/* globals.css */
@import "tailwindcss";

:root {
  --gold: #c89b3c;
  --gold-light: #f0e6d3;
  --dark-bg: #0a0e1a;
  --dark-card: #111827;
  --dark-border: #1e2a3a;
}

body {
  background-color: var(--dark-bg);
  color: var(--gold-light);
}

在组件里直接用 Tailwind 工具类,颜色用方括号语法写自定义值,比如 text-[#c89b3c]border-[#1e2a3a]


七、部署到云服务器

前提条件

  • 一台云服务器(阿里云/腾讯云/任意 VPS),系统推荐 Ubuntu 22.04
  • 服务器已安装 Node.js(推荐 v20+)和 pnpm
  • 本地已把项目打包成 lol-web.tar.gz

第一步:本地打包项目

在本地项目根目录执行:

bash 复制代码
# 先构建生产版本,确保没有报错
pnpm build

# 打包整个项目(排除 node_modules 和 .next 缓存)
tar -czf lol-web.tar.gz \
  --exclude=node_modules \
  --exclude=.next \
  --exclude=.git \
  .

第二步:上传到服务器

bash 复制代码
# 用 scp 上传(替换成你自己的服务器 IP 和用户名)
scp lol-web.tar.gz root@你的服务器IP:/home/www/

第三步:服务器上解压并安装依赖

SSH 登录服务器后:

bash 复制代码
# 进入目标目录
cd /home/www

# 创建项目目录并解压
mkdir lol-web && tar -xzf lol-web.tar.gz -C lol-web

cd lol-web

# 安装依赖(如果服务器没有 pnpm,先装:npm i -g pnpm)
pnpm install

# 构建生产版本
pnpm build

第四步:用 PM2 保持进程常驻

直接 pnpm start 的问题是关掉终端进程就停了。用 PM2 可以让 Node 进程在后台持续运行,并在服务器重启后自动恢复。

bash 复制代码
# 安装 PM2
npm i -g pm2

# 启动项目(端口默认 3000)
pm2 start pnpm --name "lol-web" -- start

# 设置开机自启
pm2 startup
pm2 save

常用 PM2 命令:

bash 复制代码
pm2 list          # 查看所有进程状态
pm2 logs lol-web  # 查看日志
pm2 restart lol-web  # 重启
pm2 stop lol-web     # 停止

第五步:配置 Nginx 反向代理(可选但推荐)

Next.js 默认跑在 3000 端口,用 Nginx 做反向代理可以:

  • 用 80/443 标准端口访问(不用在 URL 里加 :3000
  • 配置 HTTPS(SSL 证书)
  • 处理静态资源缓存

安装 Nginx:

bash 复制代码
apt update && apt install nginx -y

创建配置文件 /etc/nginx/sites-available/lol-web

nginx 复制代码
server {
    listen 80;
    server_name 你的域名或IP;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

启用配置:

bash 复制代码
ln -s /etc/nginx/sites-available/lol-web /etc/nginx/sites-enabled/
nginx -t          # 测试配置是否正确
systemctl reload nginx

第六步:配置 HTTPS(如果有域名)

用 Certbot 免费申请 Let's Encrypt 证书:

bash 复制代码
apt install certbot python3-certbot-nginx -y
certbot --nginx -d 你的域名

按提示操作,Certbot 会自动修改 Nginx 配置并配好 HTTPS,证书每 90 天自动续期。


八、更新部署流程

以后每次改了代码,重新部署的步骤:

bash 复制代码
# 本地
pnpm build
tar -czf lol-web.tar.gz --exclude=node_modules --exclude=.next --exclude=.git .
scp lol-web.tar.gz root@服务器IP:/home/www/

# 服务器
cd /home/www
rm -rf lol-web && mkdir lol-web
tar -xzf lol-web.tar.gz -C lol-web
cd lol-web
pnpm install
pnpm build
pm2 restart lol-web

九、整体架构总结

markdown 复制代码
用户浏览器
    │
    ▼
Nginx(80/443端口)
    │  反向代理
    ▼
Next.js 服务(3000端口,PM2守护)
    │
    ├── 服务端渲染页面(SSR/ISR)
    │       │
    │       ▼
    │   Riot Data Dragon API
    │   (英雄数据、图片资源)
    │
    └── 客户端交互组件
            (搜索、筛选,纯前端)

整个项目没有自己的数据库,英雄数据全部来自 Riot 官方 API,强化和出装数据是本地静态维护的。Next.js 的 ISR 缓存机制保证了性能,不会每次请求都打到 Riot 服务器。

相关推荐
你的代码僚机2 小时前
《别再被 SSO 骗了!前端单点登录原理+避坑指南》
前端
不懂代码的切图仔2 小时前
移动端h5实现横屏在线签名
前端·微信小程序
少卿2 小时前
OpenClaw 的 summarize 技能——开发者的智能摘要利器
前端·后端·程序员
麦秋2 小时前
前端静态页面自动生成(Figma MCP + VS code + Github copilot)
前端·vue.js
不甜情歌2 小时前
JS对象入门|从创建到原理,一篇吃透核心知识点
前端·javascript
DongHao2 小时前
我不想一开始就把 Axios 封装的太完美
前端·http·axios
有一个好名字3 小时前
claude code安装
linux·运维·前端
BIBABULALA3 小时前
Mini Virtual Machine — 可视化虚拟机模拟器(91行)
前端·css·css3
筱璦3 小时前
期货软件开发「启动加载页 / 初始化窗口」
前端·c#·策略模式·期货