Gallery-Portfolio 是一个风格简洁的 摄影作品展示站,你只需要将图片存放在免费的 Cloudflare R2 上(或其他任意图床),即可在这里展现你的大作。在这里你可以通过 瀑布流 的形式浏览图片,也可以 点开大图 ,查看光圈 / 快门 / ISO 等 EXIF 信息。此静态网站基于 Node.js,使用 Material Design 风格的 响应式设计,支持 日夜间模式 切换,在不同的设备上都有不错的视觉效果。
- 🚀 静态部署 - 零服务器成本,快速加载
- 🏷️ 作品分类 - 按摄影主题和地点进行分类展示
- 📱 移动端优化 - 完美适配移动设备观片
- 🖼️ 响应式设计 - 自适应布局,支持多种屏幕尺寸
- 🌙 深色/浅色主题 - 支持主题切换,优化观片体验
- ⚡ 懒加载 - 滚动时自动加载更多作品
- 🎯 自动滚动 - 一键开启自动滚动浏览
- 🖼️ 预览图优化 - 先加载预览图,点击查看高清原图
- 🔄 智能加载 - 预览图缺失时自动加载原图
- 📸 EXIF 信息 - 显示光圈、快门、ISO 等摄影参数(未完成)
- 🌍 跨平台支持 - 提供 Node.js 脚本,支持所有操作系统
- 🔗 图床兼容 - 支持任意图床服务(Cloudflare R2、阿里云 OSS、腾讯云 COS 等)
- 🎲 随机展示 - 图片以随机顺序展示,每次刷新都有不同的排列
Gallery-Portfolio/
├── index.html # 主页面
├── gallery-index.json # 图片索引文件(自动生成)
├── public/ # 静态资源
│ ├── styles.css # 主样式文件
│ ├── gallery.css # 画廊样式
│ ├── layout.js # 布局和主题切换
│ ├── gallery.js # 主画廊逻辑
│ ├── data-loader.js # 数据加载模块
│ ├── tag-filter.js # 标签筛选模块
│ ├── image-loader.js # 图片加载模块
│ ├── auto-scroll.js # 自动滚动模块
│ └── assets/ # 图标资源
├── generate-gallery-index-r2.js # Node.js图片索引生成脚本
├── generate-webp-thumbnail-r2.js # 预览图生成脚本
├── deploy.bat # Windows部署脚本
├── deploy.sh # Linux/macOS部署脚本
├── _headers # Cloudflare Pages 配置
└── package.json # 项目配置
- 登录 Cloudflare Dashboard
- 进入 R2 Object Storage 页面
- 点击 Create bucket 创建新的存储桶
- 记录存储桶名称,例如:
my-gallery
为了获得更好的访问体验,建议配置自定义域名:
- 在 R2 存储桶设置中找到 Custom Domains
- 添加你的域名,例如:
cdn.yourdomain.com - 配置 DNS 记录指向 R2 存储桶
将你的摄影作品按分类上传到 R2 存储桶:
my-gallery/
├── Hongkong/ # 分类文件夹
│ ├── DSC01475.JPG
│ └── DSC01476.JPG
├── Kyoto/
│ ├── DSC02580.JPG
│ └── DSC02581.JPG
└── 0_preview/ # 预览图目录(稍后生成)
├── Hongkong/
└── Kyoto/
在项目根目录的 .env 中配置以下变量:
R2_IMAGE_BASE_URL=https://your-domain.com
R2_IMAGE_DIR=gallery
在项目根目录创建 .env 文件(注意:不要提交到 Git):
方法一:从模板文件复制(推荐)
cp .env_template .env方法二:手动创建
R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key_id
R2_SECRET_ACCESS_KEY=your_secret_access_key
R2_BUCKET_NAME=my-gallery
R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
R2_REGION=auto
R2_IMAGE_BASE_URL=https://your-domain.com
R2_IMAGE_DIR=gallery
IMAGE_COMPRESSION_QUALITY=100
### 3. 生成预览图
安装依赖并生成 WebP 格式的预览图:
```bash
npm run r2:generate-previews这将从 R2 下载原图,生成缩略图后上传回 R2 的 0_preview 目录。
从 R2 获取文件列表并生成索引:
npm run r2:generate-index这将生成 gallery-index.json 文件,包含所有摄影作品的信息。
启动本地服务器预览效果:
npm run serve或使用其他静态服务器:
npx serve .点击下方按钮一键部署:
-
安装 Wrangler CLI:
npm install -g wrangler
-
登录 Cloudflare:
wrangler login
-
部署项目:
wrangler pages deploy . --project-name your-project-name
Windows 用户:
deploy.batLinux/macOS 用户:
chmod +x deploy.sh
./deploy.sh当你有新的摄影作品时:
- 将新图片上传到 R2 存储桶的对应分类目录
- 运行预览图生成脚本:
node generate-webp-thumbnail-r2.js - 运行索引生成脚本:
node generate-gallery-index-r2.js - 提交更新的
gallery-index.json文件到 Git - 重新部署网站
摄影作品 URL 使用以下格式:
- 原图:
https://your-domain.com/gallery/{分类}/{文件名} - 预览图:
https://your-domain.com/gallery/0_preview/{分类}/{文件名}
系统具备智能预览图检测功能:
- 如果预览图加载失败,会自动尝试加载原图
- 确保即使预览图缺失,用户仍能正常浏览作品
- 提供友好的错误提示和降级处理
编辑 generate-gallery-index-r2.js 文件中的 R2 配置,或直接修改 .env 文件:
// 配置 R2 存储桶信息
const R2_BUCKET_NAME = process.env.R2_BUCKET_NAME || 'my-gallery';
const R2_ACCOUNT_ID = process.env.R2_ACCOUNT_ID;
const R2_ACCESS_KEY_ID = process.env.R2_ACCESS_KEY_ID;
const R2_SECRET_ACCESS_KEY = process.env.R2_SECRET_ACCESS_KEY;
const R2_ENDPOINT = process.env.R2_ENDPOINT;
const R2_REGION = process.env.R2_REGION || 'auto';
const R2_IMAGE_BASE_URL = process.env.R2_IMAGE_BASE_URL;
const R2_IMAGE_DIR = process.env.R2_IMAGE_DIR || 'gallery';
const IMAGE_COMPRESSION_QUALITY = process.env.IMAGE_COMPRESSION_QUALITY || 100;编辑 generate-gallery-index-r2.js 文件中的 buildImageUrls 函数:
function buildImageUrls(categoryName, fileName, fileExt) {
// 使用自定义域名
const originalUrl = `https://cdn.yourdomain.com/gallery/${categoryName}/${fileName}.${fileExt}`;
const previewUrl = `https://cdn.yourdomain.com/gallery/0_preview/${categoryName}/${fileName}.webp`;
// 或使用 R2 默认域名
// const originalUrl = `https://your-bucket.your-subdomain.r2.cloudflarestorage.com/gallery/${categoryName}/${fileName}.${fileExt}`;
// const previewUrl = `https://your-bucket.your-subdomain.r2.cloudflarestorage.com/gallery/0_preview/${categoryName}/${fileName}.webp`;
return { originalUrl, previewUrl };
}
## 🛠️ 开发
### 项目依赖
```json
{
"devDependencies": {
"serve": "^14.2.1"
}
}npm run build- 构建脚本(静态网站无需构建)
npm run serve- 启动本地服务器npm run local:generate-index- 生成作品索引npm run local:generate-previews- 生成预览图
项目采用模块化设计,主要模块包括:
- DataLoader - 负责从 JSON 文件加载摄影作品数据
- TagFilter - 处理作品分类筛选功能
- ImageLoader - 管理作品加载和布局
- AutoScroll - 自动滚动功能
- Gallery - 主画廊控制器
项目支持图片随机展示,提供更好的浏览体验:
- 完全随机 - 每次刷新页面或切换分类时,图片都会重新随机排列
- 分类内随机 - 单个分类内的图片也会随机展示
- 全局随机 - "全部"标签下的图片会从所有分类中随机混合展示
- 使用 JavaScript 的
sort()方法配合Math.random()实现随机排序 - 每次调用数据加载方法时都会重新随机排序
- 保持原有的去重逻辑,避免重复图片出现
在 public/styles.css 中修改 CSS 变量:
:root {
--primary-color: #4caf50; /* 主色调 */
--background-color: #ffffff; /* 背景色 */
--text-color: #333333; /* 文字颜色 */
}在 public/gallery.css 中调整:
.gallery {
gap: 0.8em; /* 作品间距 */
width: 80%; /* 画廊宽度 */
max-width: 1200px; /* 最大宽度 */
}网站支持以下断点:
- 移动端 (< 600px): 2 列布局
- 平板 (600px - 900px): 3 列布局
- 桌面 (900px - 1200px): 4 列布局
- 大屏 (1200px - 1500px): 5 列布局
- 超大屏 (> 1500px): 6 列布局
-
作品不显示
- 检查
gallery-index.json文件是否存在 - 确认作品 URL 是否正确
- 检查网络连接
- 确认本地目录与远程图床已同步
- 检查
-
预览图生成失败
- 确认已安装 ImageMagick
- 检查源作品路径是否正确
- 确认有足够的磁盘空间
-
部署失败
- 确认已安装并登录 Wrangler
- 检查项目名称是否可用
- 确认文件权限正确
-
图片无法加载
- 检查图床域名配置是否正确
- 确认图片文件已上传到图床
- 检查图床服务的访问权限设置
在浏览器控制台中查看详细日志:
// 查看加载的作品数据
console.log(window.gallery.dataLoader.galleryData);
// 查看当前选中的分类
console.log(window.gallery.tagFilter.getCurrentTag());ISC License
欢迎提交 Issue 和 Pull Request!
如有问题,请提交 GitHub Issue.
Enjoy your own Gallery! 🎉