feat: 新增共享记事本页签(iframe 嵌入 + 存活校验)与集中配置
- 新增 whiteboard 模块:iframe 嵌入 f.zikai.wang/wb/shared,骨架屏+降级外链 - 存活校验:模块声明 requiresAlive,启动时 no-cors 探测 /health 一次, 服务挂掉则隐藏页签(刷新页面才重探) - 集中配置 src/config/app.config.js:白板 URL/探针/默认记事本 id 统一管理 - 容错强化:注册表/路由/useProjects 单模块异常不影响其他页签,删除一个页签 仅需删其模块文件夹并重新 build - i18n:tabs.whiteboard / common.serviceUnavailable / whiteboard.openExternal - README 精简重写:仅保留项目结构、基础设施、Ubuntu 从0安装、新增页签
This commit is contained in:
236
README.md
236
README.md
@@ -1,209 +1,115 @@
|
||||
# mainPage · 作品集主页
|
||||
|
||||
Zikai 的作品集主页 -- 一个 **Vue 3 模块化**的多项目展示站点。
|
||||
采用**浅色极简**美术风格,**中英双语**并支持**懒加载**(默认中文,只看中文的访客不会下载英文资源)。
|
||||
设计目标:高内聚低耦合、可扩展 -- 后续每个新项目都是一个独立「模块」,自动生成页签与路由。
|
||||
|
||||
> 这是「主页」项目本身。它展示的第一个项目页签是 448/449 移动游戏毕设,
|
||||
> 详见同级目录下的 `/root/html/448/README.md` 与 `/root/html/449/README.md`。
|
||||
Zikai 的作品集主页 -- Vue 3 模块化多项目展示站。浅色极简、中英双语(英文按需懒加载)。
|
||||
每个项目页签是一个独立「模块」,由注册表自动生成页签与路由 -- 新增/删除页签只增删一个文件夹,互不影响。
|
||||
|
||||
---
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 层 | 选型 |
|
||||
|---|---|
|
||||
| 框架 | Vue 3(`<script setup>` Composition API) |
|
||||
| 构建 | Vite 5 |
|
||||
| 路由 | vue-router 4(history 模式,路由表由模块注册表动态生成) |
|
||||
| 国际化 | vue-i18n 9(中文同步注入,英文动态 `import()` 懒加载) |
|
||||
| 样式 | 原生 CSS + CSS 变量令牌(无 UI 框架,零运行时样式依赖) |
|
||||
|
||||
Node 版本要求:≥ 18(本项目在 Node 18.19 + npm 9.2 下开发与构建)。
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
mainPage/
|
||||
├── index.html # Vite 入口模板
|
||||
├── index.html
|
||||
├── package.json
|
||||
├── vite.config.js # ★ 构建输出配置(见下「构建与部署」)
|
||||
├── .gitignore
|
||||
├── README.md # 本文件
|
||||
├── public/
|
||||
│ └── favicon.svg # 站点图标
|
||||
├── vite.config.js # 构建输出到 /root/html(emptyOutDir=false,不清空既有文件)
|
||||
├── 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 # 重置 + 排版基础
|
||||
├── main.js # 应用入口(挂载 i18n / router / 全局样式)
|
||||
├── App.vue # 根布局:顶栏 + 标签导航 + <router-view> + 页脚
|
||||
├── config/
|
||||
│ └── app.config.js # ★ 集中配置:外部服务 URL(白板地址 / 存活探针等)
|
||||
├── i18n/ # 国际化(中文同步注入;英文动态 import() 懒加载)
|
||||
│ ├── index.js
|
||||
│ └── locales/{zh-CN,en}.js
|
||||
├── router/index.js # 路由表由模块注册表自动生成
|
||||
├── modules/ # ★ 扩展点:每个页签一个文件夹
|
||||
│ ├── index.js # 注册表(import.meta.glob 约定式收集,带容错)
|
||||
│ ├── mobile-game/ # 移动游戏项目页签
|
||||
│ ├── whiteboard/ # 共享记事本页签(iframe 嵌入 + 存活校验)
|
||||
│ └── calendar/ # 隐藏页(仅手动访问 /cqy)
|
||||
├── components/ # 共享组件(TabNav / LanguageSwitcher / ui 基元)
|
||||
├── composables/ # useProjects(页签+存活联动)/ useLiveness / useI18nLazy / useLocale
|
||||
└── styles/ # variables.css(主题令牌)+ base.css
|
||||
```
|
||||
|
||||
---
|
||||
## 模块机制(高内聚低耦合)
|
||||
|
||||
## 架构要点
|
||||
|
||||
### 1. 模块化扩展(高内聚低耦合)
|
||||
|
||||
**新增一个项目页签 = 新建 `src/modules/<新项目>/` 文件夹**,无需改动导航或路由代码。
|
||||
|
||||
- `src/modules/index.js` 用 `import.meta.glob('./*/index.js', { eager: true })` 约定式收集所有模块。
|
||||
- `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') // 懒加载组件
|
||||
id: 'whiteboard', // 唯一标识 + 路由 path
|
||||
tabKey: 'tabs.whiteboard', // i18n 键
|
||||
order: 2, // 页签排序
|
||||
component: () => import('./Whiteboard.vue'), // 懒加载组件(独立 chunk)
|
||||
requiresAlive: 'https://f.zikai.wang/health' // 可选:存活探针 URL,挂掉则隐藏页签
|
||||
}
|
||||
```
|
||||
- `TabNav.vue` 遍历注册表渲染页签;`router/index.js` 遍历注册表生成路由。
|
||||
- 模块自包含组件、数据,模块间无直接引用 -> 高内聚低耦合。
|
||||
- `TabNav` 遍历注册表渲染页签;`router` 遍历注册表生成路由。
|
||||
- 删除一个页签 = 删 `src/modules/<id>/` 文件夹并重新 build,其余页签不受影响。
|
||||
|
||||
### 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)独立存在。
|
||||
声明了 `requiresAlive` 的模块,应用启动时对探针 URL 做一次 `no-cors` fetch 探测(4s 超时)。
|
||||
探测返回前该页签不显示(避免闪烁);服务存活则显示,不可达则保持隐藏(刷新页面才重探)。
|
||||
|
||||
### 3. 浅色极简美术
|
||||
## 依赖的基础设施
|
||||
|
||||
主题令牌集中在 `src/styles/variables.css`:白底 `#fff` / 浅灰面 `#f7f8fa`、单一靛蓝强调色 `#4f46e5`、圆角 12px、柔和阴影、细线边框、充足留白。无深色、无渐变铺底、无霓虹;悬浮微交互克制(轻微上移 + 阴影加深)。
|
||||
| 项 | 要求 |
|
||||
|---|---|
|
||||
| Node.js | ≥ 18(开发于 18.19 + npm 9.2) |
|
||||
| Web 服务器 | Apache 2.4(启用 `mod_rewrite`),对外静态服务 `/root/html` |
|
||||
| SPA 回退 | history 模式需站点根 `.htaccess` 回退到 `index.html`(见下) |
|
||||
|
||||
---
|
||||
> 共享记事本页签通过 iframe 嵌入外部服务(默认 `https://f.zikai.wang/wb/shared`),URL 在 `src/config/app.config.js` 集中配置。该服务需公开且允许被 iframe 嵌入。
|
||||
|
||||
## 开发
|
||||
## Ubuntu 从 0 安装
|
||||
|
||||
```bash
|
||||
cd /root/zikai/mainPage
|
||||
npm install # 首次安装依赖
|
||||
npm run dev # 启动开发服务器 (http://localhost:5173)
|
||||
# 1. 安装 Node.js 18
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# 2. 取代码
|
||||
git clone https://git.zikai.wang/zikai/zMainPage.git mainPage
|
||||
cd mainPage
|
||||
npm install
|
||||
|
||||
# 3. 构建(产物输出到 /root/html,不清空既有文件)
|
||||
npm run build
|
||||
|
||||
# 4. 安装并启用 Apache
|
||||
sudo apt-get install -y apache2
|
||||
sudo a2enmod rewrite
|
||||
```
|
||||
|
||||
开发服务器配置了代理:`/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` 同步可见):
|
||||
站点根放 `.htaccess`(Apache 需 `AllowOverride All`)做 SPA 回退:
|
||||
|
||||
```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` 下)。
|
||||
|
||||
---
|
||||
把 `/root/html`(或 `/var/www/html`)设为 `DocumentRoot`,访问站点即可。开发预览用 `npm run dev`(http://localhost:5173)。
|
||||
|
||||
## 如何新增一个项目页签
|
||||
|
||||
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`。
|
||||
1. 复制 `src/modules/whiteboard/`(或 `mobile-game/`)为 `src/modules/<新项目>/`。
|
||||
2. 改 `<新项目>/index.js` 的 `id` / `tabKey` / `order` / `component`。
|
||||
3. 在 `src/i18n/locales/zh-CN.js` 与 `en.js` 的 `tabs` 下加对应文案。
|
||||
4. `npm run build` -- 页签与路由自动出现,无需改导航或路由代码。
|
||||
|
||||
---
|
||||
|
||||
## 已知限制
|
||||
## 开发命令
|
||||
|
||||
- 排行榜依赖 `/449/449rest.php`(PHP + MySQL)在线;后端不可用时组件优雅降级显示「服务暂不可用」。
|
||||
- 演示视频 `/448/ml/449ml.mp4`(约 34 MB)用 `preload="none"`,点播才加载。
|
||||
- 448/449 的 README 总结了既有项目(构建产物,无源码),见各自目录。
|
||||
```bash
|
||||
npm install # 首次安装依赖
|
||||
npm run dev # 开发服务器 http://localhost:5173
|
||||
npm run build # 构建到 /root/html
|
||||
npm run preview # 本地预览构建产物
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user