Files
zMainPage/README.md
Zikai 0adb320a47 docs: 部署节更正为 Apache + 补充 SPA .htaccess 回退说明
实际对外服务是 Apache 2.4(非 nginx),DocumentRoot /var/www/html。
history 模式下直接访问 /mobile-game 会 404,已用站点根 .htaccess 回退
(该文件不纳入本项目仓库,仅文档说明)。
2026-07-12 15:24:34 +00:00

210 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# mainPage · 作品集主页
Zikai 的作品集主页 -- 一个 **Vue 3 模块化**的多项目展示站点。
采用**浅色极简**美术风格,**中英双语**并支持**懒加载**(默认中文,只看中文的访客不会下载英文资源)。
设计目标:高内聚低耦合、可扩展 -- 后续每个新项目都是一个独立「模块」,自动生成页签与路由。
> 这是「主页」项目本身。它展示的第一个项目页签是 448/449 移动游戏毕设,
> 详见同级目录下的 `/root/html/448/README.md` 与 `/root/html/449/README.md`。
---
## 技术栈
| 层 | 选型 |
|---|---|
| 框架 | Vue 3`<script setup>` Composition API |
| 构建 | Vite 5 |
| 路由 | vue-router 4history 模式,路由表由模块注册表动态生成) |
| 国际化 | vue-i18n 9中文同步注入英文动态 `import()` 懒加载) |
| 样式 | 原生 CSS + CSS 变量令牌(无 UI 框架,零运行时样式依赖) |
Node 版本要求:≥ 18本项目在 Node 18.19 + npm 9.2 下开发与构建)。
---
## 目录结构
```
mainPage/
├── index.html # Vite 入口模板
├── package.json
├── vite.config.js # ★ 构建输出配置(见下「构建与部署」)
├── .gitignore
├── README.md # 本文件
├── public/
│ └── favicon.svg # 站点图标
└── src/
├── main.js # 应用入口(挂载 i18n、router、全局样式
├── App.vue # 根布局:顶栏 + 标签导航 + <router-view> + 页脚
├── i18n/ # 国际化(懒加载核心)
│ ├── index.js # i18n 实例仅同步注入中文loadLocaleAsync() 动态切语言
│ └── locales/
│ ├── zh-CN.js # 中文(默认,打进主 chunk
│ └── en.js # 英文(动态 import() -> 独立 chunk切换时才下载
├── router/
│ └── index.js # 路由表遍历模块注册表自动生成
├── modules/ # ★★★ 扩展点:每个项目一个模块文件夹
│ ├── index.js # 模块注册表import.meta.glob 约定式收集)
│ └── mobile-game/ # 第一个页签448/449 移动游戏项目
│ ├── index.js # 模块元数据id / tabKey / order / 懒加载组件)
│ ├── MobileGame.vue # 项目展示主页
│ ├── components/
│ │ ├── HeroSection.vue # 顶部项目概览横幅
│ │ ├── ScreenshotCarousel.vue# 截图轮播(复用 /448/1..3.jpg
│ │ ├── VersionTimeline.vue # 版本演进时间线
│ │ ├── TeamCard.vue # 团队成员卡片
│ │ └── Leaderboard.vue # 排行榜AJAX 调 /449/449rest.php失败降级
│ └── data/
│ ├── versions.js # 版本数据448 各版本信息)
│ └── team.js # 团队成员数据
├── components/ # 全局共享组件
│ ├── TabNav.vue # 标签页导航(由模块注册表驱动,自动生成页签)
│ ├── LanguageSwitcher.vue # 中/英切换按钮
│ └── ui/ # 基础 UI 基元
│ ├── Card.vue
│ └── Tag.vue
├── composables/ # 组合式逻辑
│ ├── useProjects.js # 读取已注册模块列表
│ └── useI18nLazy.js # 语言懒加载切换逻辑
└── styles/
├── variables.css # 主题令牌(浅色极简:色板/圆角/阴影/间距)
└── base.css # 重置 + 排版基础
```
---
## 架构要点
### 1. 模块化扩展(高内聚低耦合)
**新增一个项目页签 = 新建 `src/modules/<新项目>/` 文件夹**,无需改动导航或路由代码。
- `src/modules/index.js``import.meta.glob('./*/index.js', { eager: true })` 约定式收集所有模块。
- 每个模块 `index.js` 默认导出元数据:
```js
export default {
id: 'mobile-game', // 唯一标识,同时作路由 path
tabKey: 'tabs.mobileGame', // i18n 键,页签标题
order: 1, // 页签排序
component: () => import('./MobileGame.vue') // 懒加载组件
}
```
- `TabNav.vue` 遍历注册表渲染页签;`router/index.js` 遍历注册表生成路由。
- 模块自包含组件、数据,模块间无直接引用 -> 高内聚低耦合。
### 2. i18n 懒加载(中文页不加载英文资源)
- 创建 i18n 实例时**只同步注入中文** `zh-CN`(随主 chunk 下发)。
- `en.js` 通过 `() => import('./locales/en.js')` 注册Vite/Rollup 自动拆成**独立 chunk** `en.[hash].js`。
- 切换英文时 `useI18nLazy` 先 `await import()` 拉取英文 chunk`mergeLocaleMessage` 后再切 `locale`。
- 结果:只看中文的访客**永不请求英文 chunk**;首次切英文才下载,之后切换无网络请求。
- 构建产物可见 `js/mainPage/en.[hash].js`(约 0.27 KB独立存在。
### 3. 浅色极简美术
主题令牌集中在 `src/styles/variables.css`:白底 `#fff` / 浅灰面 `#f7f8fa`、单一靛蓝强调色 `#4f46e5`、圆角 12px、柔和阴影、细线边框、充足留白。无深色、无渐变铺底、无霓虹悬浮微交互克制轻微上移 + 阴影加深)。
---
## 开发
```bash
cd /root/zikai/mainPage
npm install # 首次安装依赖
npm run dev # 启动开发服务器 (http://localhost:5173)
```
开发服务器配置了代理:`/448`、`/449` 请求转发到 `http://localhost:8080`
(假设该端口有静态服务器在跑,否则截图/排行榜/视频会 404但页面其余部分正常
开发时可临时用 `python3 -m http.server 8080 --directory /root/html` 提供这些静态资源。
## 构建与打包
```bash
npm run build # 产物输出到 /root/html
```
### 输出路径与安全策略(`vite.config.js`
- `build.outDir = '/root/html'`**`emptyOutDir = false`**(★ 不清空 outDir
`/root/html` 已含 448/449/旧 js/css 等既有内容,绝不能被构建清空。
- 用 `mainPage/` 命名空间子目录避免与 `/root/html/js`、`/root/html/css` 旧文件冲突:
- JS -> `js/mainPage/[name].[hash].js`
- CSS -> `css/mainPage/[name].[hash].css`
- 其他资源 -> `assets/mainPage/[name].[hash][extname]`
- `base = '/'`,引用既有 448/449 资源用站点根绝对路径(`/448/...`、`/449/...`)。
### 构建产物示例
```
/root/html/
├── index.html # 入口Vite 注入 <script>/<link>
├── favicon.svg
├── js/mainPage/
│ ├── index.[hash].js # 主 chunk含 Vue/router/中文 i18n
│ ├── MobileGame.[hash].js # 移动游戏页(懒加载)
│ └── en.[hash].js # 英文语言包(懒加载,仅切英文时下载)
└── css/mainPage/
├── index.[hash].css # 全局样式
└── MobileGame.[hash].css # 移动游戏页样式
```
## 预览构建产物
```bash
npm run preview # 本地预览构建后的产物
```
## 部署
构建产物直接落在站点根 `/root/html`,由 Web 服务器以该目录为根提供静态服务。
本机实际情况:**Apache 2.4**(非 nginx对外服务 `https://zikai.wang`
`DocumentRoot /var/www/html``/var/www/html` 与 `/root/html` 内容同步),
`mod_rewrite` 已启用且 `AllowOverride All`。
### ★ SPA 回退history 模式必需)
本站用 Vue Router **history 模式**,客户端路由如 `/mobile-game` 并非真实文件。
直接访问或刷新此类 URL 时,服务器会找不到文件而 404。已在 `/root/html/.htaccess`
配置回退(该文件在 `/var/www/html` 同步可见):
```apache
RewriteEngine On
# 真实文件/目录直接放行
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 其余路由回退到 index.html由前端路由处理
RewriteRule ^ index.html [L]
```
> 该 `.htaccess` 是站点根的部署配置,不属于本项目源码,故未纳入 `mainPage` git 仓库。
> 若重新部署/迁移服务器,需在站点根放置此文件(并确保 Apache 允许 `.htaccess` 覆盖)。
主页引用的 `/448/...`、`/449/...` 资源必须能从站点根访问到448/449 目录本就在 `/root/html` 下)。
---
## 如何新增一个项目页签
1. 复制 `src/modules/mobile-game/` 为 `src/modules/<新项目>/`。
2. 编辑 `<新项目>/index.js`,改 `id`、`tabKey`、`order`、`component` 指向。
3. 在 `src/i18n/locales/zh-CN.js` 与 `en.js` 的 `tabs` 下新增对应的 `tabKey` 文案。
4. 实现模块主组件与子组件(可复用 `components/ui/` 基元)。
5. `npm run build` -- 页签与路由自动出现,无需改动 `TabNav` 或 `router`。
---
## 已知限制
- 排行榜依赖 `/449/449rest.php`PHP + MySQL在线后端不可用时组件优雅降级显示「服务暂不可用」。
- 演示视频 `/448/ml/449ml.mp4`(约 34 MB用 `preload="none"`,点播才加载。
- 448/449 的 README 总结了既有项目(构建产物,无源码),见各自目录。