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

本文记录了这个英雄联盟海克斯大乱斗攻略网站的完整开发思路、代码结构,以及如何把它部署到自己的云服务器上。适合有一点前端基础、想了解 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 服务器。

相关推荐
mldong5 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60616 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角7 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!7 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰8 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi9 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen10 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马10 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒11 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端