本博客简要
用 React + Vite 折腾的个人博客
最近花时间做了个个人主页+博客,技术栈 React + Vite + Tailwind CSS
技术栈#
很常规的前端技术栈:
- React 18
- Vite 5
- Tailwind CSS
- Framer Motion
- react-markdown
- highlight.js
主要功能#
主题切换#
做了两个主题:亮/深
背景特效#
三种背景:纯色、图片、点阵。
图片背景用了三层遮罩:
- 底层图片
scale-110+blur-md做模糊效果 - 渐变遮罩增强可读性
- 整体遮罩柔化背景
图片会缓存到 localStorage,用 Canvas 转成 base64 存起来,有效期 7 天。这样第二次加载就不用等了。
const canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
ctx.drawImage(img, 0, 0)
const dataUrl = canvas.toDataURL('image/jpeg', 0.8)
localStorage.setItem('bg_img', dataUrl)自定义光标#
桌面端做了个自定义光标,用 requestAnimationFrame 让它跟着鼠标跑
检测可交互元素的逻辑:
- A、BUTTON、INPUT 这些标签
cursor: pointer样式data-clickable属性- 还会向上查找父元素
移动端自动禁用,毕竟手机上用不着。
Markdown 文章系统#
文章都放在 docs/ 目录下,通过目录结构来定义分类:
docs/
├── 技术/ ← 这就是"技术"分类
│ ├── react.md
│ └── vue.md
├── 生活/ ← 这就是"生活"分类
│ └── travel.md
└── welcome.md ← 根目录的归到"未分类"每个 Markdown 文件开头写 Frontmatter:
---
title: "文章标题"
excerpt: "简短描述"
tags: ["React", "前端"]
date: "2024-01-01"
author: "XiaoXian"
password: "123456" # 可选设置密码
visible: true # 设为 false 可以隐藏文章
---
正文内容...自动化脚本#
写了两个脚本处理文章:
generate-articles-manifest.js - 构建时扫描 docs/ 目录,解析 Frontmatter,生成 manifest.json 索引文件。
docs-watcher-service.js - 预览模式下监听 docs/ 变化,自动同步到 dist/docs/,还会更新索引。这样本地改完文章刷新浏览器就能看到。
Markdown 渲染#
react-markdown + 一堆插件:
remark-gfm- 支持表格、删除线、任务列表rehype-highlight- 代码高亮rehype-raw- 支持原始 HTML
还自定义了一些组件,比如代码块带复制按钮,图片可以点击预览。
Markdown 支持的语法#
基础文本#
支持 粗体、斜体、删除线、行内代码。
列表#
- 无序列表项 1
- 无序列表项 2
- 嵌套列表
- 还能继续嵌套
- 有序列表项 1
- 有序列表项 2
- 有序列表项 3
任务列表#
- 已完成的任务
- 未完成的任务
- 另一个待办
引用块#
这是一个引用块
可以写多行
还能嵌套引用
代码块#
支持多种语言的语法高亮:
// JavaScript 代码
const greeting = (name) => {
console.log(`Hello, ${name}!`)
}
greeting('World')# Python 代码
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))/* CSS 代码 */
.card {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
}表格#
| 功能 | 支持 | 备注 |
|---|---|---|
| 语法高亮 | ✓ | highlight.js |
| 表格 | ✓ | GFM 扩展 |
| 任务列表 | ✓ | GFM 扩展 |
| 图片预览 | ✓ | 自定义组件 |
链接和图片#
文章列表功能#
- 两种视图 - 卡片模式(大图展示)和紧凑模式(列表风格)
- 搜索 - 标题、摘要、标签都能搜
- 筛选 - 按分类或标签过滤
- 懒加载 - 滚动到底部自动加载更多
阅读文章时:
- 顶部有滚动进度条
- 右侧自动生成目录(点击可跳转)
- 支持沉浸式阅读模式(隐藏侧边栏)
作品展示页#
这个页面做得比较花哨,支持图片/视频全屏展示,做了个沉浸模式。
布局设计:
- 左上角:作品标题(带阴影效果)
- 左下角:技术栈 + 简介
- 右上角:访问链接按钮
- 底部:上一个/下一个、进度点、分类筛选、沉浸模式切换
桌面端右侧有固定的分类栏,移动端点击分类会弹出选择弹窗。
配置系统#
所有配置都在 src/config.js 里,改这一个文件就能定制整个网站:
export const APP_CONFIG = {
site: {
title: 'XiaoXian',
subtitle: 'Darf / 弧渊',
description: '欢迎来到我的个人主页👋'
},
theme: {
primaryColor: { light: '#5B89D2', dark: '#5B89D2' }
},
navigation: [
{ name: '主页', path: '/' },
{ name: '文章', path: '/articles' },
{ name: '作品', path: '/projects' }
],
// ... 其他配置
}Context 状态管理#
没用 Redux,直接上 Context API。做了 5 个 Context:
ThemeContext- 主题BackgroundContext- 背景LayoutContext- 布局模式ArticleSettingsContext- 文章视图设置ConfigContext- 配置注入
每个 Context 自己管自己的状态,互不干扰。
文章监听服务#
预览模式下会启动一个 Node 服务监听 docs/ 目录:
const watcher = chokidar.watch('docs', {
ignored: /(^|[\/\\])\../,
persistent: true
})
watcher
.on('add', path => copyFile(path))
.on('change', path => copyFile(path))
.on('unlink', path => deleteFile(path))改完文章刷新浏览器就能看到。
动画效果#
页面切换、列表项加载都用了 Framer Motion 做动画:
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
{/* 内容 */}
</motion.div>列表还做了交错动画,一个个依次出现,比较有层次感。
写在最后#
这个博客系统从最开始只想做个简单的文章列表,到现在有了主题切换、自定义光标、沉浸式阅读这些功能,前前后后折腾了挺久。
代码都开源了,感兴趣的话可以自己拿去改改。配置很灵活,改 config.js 就能定制成你自己的风格。
有 bug 或者建议欢迎提 Issue~