# hello-blog
**Repository Path**: dkbnull/hello-blog
## Basic Information
- **Project Name**: hello-blog
- **Description**: 个人博客系统,用于分享技术文章、开发笔记与生活感悟。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: https://blog.wbnull.cn
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-03-11
- **Last Updated**: 2026-07-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
Hello Blog
---
## 项目简介
Hello Blog 是一个基于 Vue 3 + Vite 构建的个人博客系统,用于分享技术文章、开发笔记与生活感悟。
## 功能特性
### 📝 文章管理
- 文章分类浏览
- 文章标签筛选
- 支持 HTML 和 Markdown 两种格式文章展示
- 文章内容缓存,避免重复请求
- 文章与分类运行时动态加载,新增文章无需编译(fetch `categories.json` + 各分类 `meta.json`)
### 🔍 搜索功能
- 全站模糊搜索,支持按标题、分类、标签匹配
- 独立搜索结果页面
### 🎨 界面设计
- 响应式布局,适配桌面端/移动端
- 深色/浅色模式切换(状态持久化至 localStorage)
- CSS 变量统一主题配色(主题色 #42b883)
- 卡片式设计,简洁美观
- 默认布局组件(Header + Main + Footer + BackToTop)
### ⚡ 性能优化
- 路由懒加载
- 构建资源自动哈希
- Vite 手动分包(vue/markdown 独立 chunk)
- API 与组件自动导入(unplugin-auto-import / unplugin-vue-components)
### 🔎 SEO 优化
- 构建时注入 SEO 元标签(description、keywords、OG、Twitter Card)
- 构建时注入 JSON-LD 结构化数据(WebSite + SearchAction)
- 运行时路由级 SEO 元信息自动更新
- 文章详情页动态 SEO
- Canonical URL 设置
### 📊 数据统计
- 百度统计集成
- 页面浏览自动上报
- 自定义事件上报支持
### 📄 分页与排序
- 文章列表分页(每页 10 篇)
- 按日期升序/降序排序
## 技术栈
| 技术 | 版本 | 说明 |
|--------------------------|--------|-------------|
| Vue | 3.5.30 | 前端框架 |
| Vue Router | 5.0.3 | 路由管理 |
| Pinia | 3.0.4 | 状态管理 |
| Vite | 8.0.8 | 构建工具 |
| marked | 17.0.4 | Markdown 解析 |
| unplugin-auto-import | 21.0.0 | API 自动导入 |
| unplugin-vue-components | 32.0.0 | 组件自动导入 |
| vite-plugin-vue-devtools | 8.1.1 | Vue 开发者工具 |
## 项目结构
```
hello-blog/
├── plugins/ # Vite 插件
│ └── vite-plugin-seo-analytics.js # SEO 分析构建插件
├── public/
│ ├── articles/ # 文章目录(运行时 fetch 加载)
│ │ ├── categories.json # 分类配置(id、name、icon、tags、image)
│ │ ├── {category}/ # 分类目录,内放 {id}-{title}.html 文章
│ │ │ └── meta.json # 文章元数据清单(title/ext/date/tags/image 等)
│ │ ├── frontend/
│ │ └── backend/
│ ├── icons/ # 分类图标(categories.json 的 icon 字段引用)
│ ├── images/ # 文章封面图(按分类子目录组织)
│ │ ├── frontend/
│ │ └── backend/
│ └── favicon.svg # Logo
├── src/
│ ├── assets/ # 资源文件(default.svg 兜底图等)
│ ├── components/ # 组件
│ │ ├── BackToTop.vue # 回到顶部
│ │ ├── Footer.vue # 底部
│ │ ├── Header.vue # 顶部导航
│ │ ├── Pagination.vue # 分页
│ │ ├── PostCard.vue # 文章卡片
│ │ ├── Sidebar.vue # 侧边栏
│ │ └── SortControl.vue # 排序控制
│ ├── composables/ # 组合式函数
│ │ ├── usePagination.js # 分页逻辑
│ │ └── useSeo.js # SEO 元信息管理
│ ├── data/ # 数据层
│ │ ├── articles.js # 文章查询/搜索/内容加载
│ │ └── data.js # 运行时加载分类与文章元数据(fetch + ref)
│ ├── layouts/
│ │ └── DefaultLayout.vue # 默认布局
│ ├── plugins/
│ │ └── seoAnalytics.js # SEO 分析运行时插件
│ ├── router/
│ │ └── index.js # 路由配置
│ ├── stores/
│ │ └── app.js # 全局状态(深色模式等)
│ ├── views/ # 页面
│ │ ├── About.vue # 关于
│ │ ├── ArticleDetail.vue # 文章详情
│ │ ├── Home.vue # 首页/分类页
│ │ ├── NotFound.vue # 404
│ │ └── Search.vue # 搜索
│ ├── App.vue # 根组件(启动时触发数据加载)
│ ├── main.js # 入口文件
│ └── style.css # 全局样式(含 CSS 变量)
├── .env # 环境变量
├── index.html # HTML 入口
├── vite.config.js # Vite 配置
└── package.json
```
## 如何添加文章
文章与分类在**运行时**通过 fetch `categories.json` + 各分类 `meta.json` 动态加载,新增文章无需编译,刷新页面即可生效。
### 1. 新增文章
1. 将文章文件放入对应分类目录,命名格式为 `{id}-{title}.html` 或 `{id}-{title}.md`:
```
public/articles/
├── frontend/
│ ├── 01-Vue 3 新特性详解.html
│ └── 02-TypeScript 入门指南.html
├── backend/
│ ├── 01-Node.js 性能优化技巧.html
│ └── ...
└── ...
```
- `id`:文章在分类下的唯一标识(如 01、02),按倒序排列展示
- `title`:文章标题,需与文件名中 `-` 后的部分一致
2. 在该分类的 `meta.json` 中添加一条文章记录:
```json
{
"articles": {
"02": {
"title": "TypeScript 入门指南",
"ext": "html",
"date": "2026-06-28",
"author": "null",
"tags": ["TypeScript", "前端"],
"image": "typescript.svg"
}
}
}
```
| 字段 | 类型 | 必填 | 说明 |
|----------|----------|------|--------------------------------------------|
| `title` | string | 是 | 文章标题,需与文件名一致 |
| `ext` | string | 是 | 文件扩展名(`html` 或 `md`) |
| `date` | string | 是 | 发布日期(YYYY-MM-DD) |
| `author` | string | 否 | 作者,默认 `null` |
| `tags` | string[] | 否 | 标签数组,未配置时继承分类默认 tags |
| `image` | string | 是 | 封面图文件名,放在 `public/images/{分类}/` |
3. 将封面图放入 `public/images/{分类}/` 目录:
```
public/images/
├── frontend/
│ ├── vue3.svg
│ └── typescript.svg
└── backend/
└── nodejs.svg
```
`meta.json` 中填写文件名即可,运行时自动解析为 `/images/{分类}/{文件名}`。
### 2. 新增分类
1. 在 `public/articles/` 下创建分类目录(目录名即分类 id),并添加 `meta.json`:
```json
{
"articles": {}
}
```
2. 在 `public/articles/categories.json` 添加分类配置:
```json
{
"categories": [
{
"id": "frontend",
"name": "前端开发",
"icon": "frontend.svg",
"image": "frontend.png",
"tags": ["前端"]
}
]
}
```
- `icon`:分类图标,放在 `public/icons/` 目录,填写文件名
- `image`:分类默认封面图,放在 `public/images/{分类}/` 目录,填写文件名
- `tags`:分类默认标签,文章未配置 tags 时继承
3. `icon` 字段支持三种写法:文件名(`frontend.svg` → 解析为 `/icons/frontend.svg`)、`/` 开头的 public 路径、完整 URL。
### 3. 数据加载机制
- 应用启动时(`App.vue` 的 `onMounted`)调用 `loadArticlesData()`
- 并发 fetch `categories.json` + 所有分类的 `meta.json`
- 数据存入 `ref`,组件通过 `computed` 自动响应更新
- 加载过程中 Sidebar 和 Home 显示 loading 动画
- 文章内容(HTML/MD 文件)在访问详情页时按需 fetch,并缓存避免重复请求
## 许可证
Apache License 2.0
---