相册功能优化:放照片就能自动显示

发表于 2026-01-29 15:00 981 字 5 min read

吕小布 avatar

吕小布

The first step is to establish that something is possible; then probability will occur.

暂无目录
优化博客相册功能,实现自动扫描文件夹中的照片,无需手动配置,放进去就能显示。

博客的相册功能做了一次优化,现在只需要把照片放到指定文件夹,页面就会自动显示,不用再手动配置每张照片的路径了。

原来的问题

之前的相册功能需要在 YAML 配置文件中手动填写每张照片的路径:

原来的配置方式

- id: "travel-2023"
  title: "旅行 2023"
  cover: "/img/cover/3.webp"
  photos:
    - "/img/gallery/travel-2023/1.jpg"
    - "/img/gallery/travel-2023/2.jpg"
    - "/img/gallery/travel-2023/3.jpg"
    # 每加一张照片都要手动添加...

这种方式有几个明显的痛点:

问题描述
繁琐每张照片都要手动写路径
易错文件名写错就显示不出来
不直观想加照片还得打开配置文件

我想要的效果很简单:把照片丢进文件夹,刷新页面就能看到

解决方案

实现一个自动扫描功能,在构建时读取文件夹中的所有图片。

文件夹结构

public/img/gallery/
├── travel-2023/        # 相册文件夹(文件夹名 = 相册ID)
│   ├── 01.jpg
│   ├── 02.jpg
│   └── 03.webp
├── daily/
│   ├── photo1.png
│   └── photo2.webp
└── ...

文件夹结构示意

核心代码

创建一个扫描函数,读取指定文件夹中的所有图片:

import fs from 'node:fs';
import path from 'node:path';

const GALLERY_DIR = 'public/img/gallery';
const IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.webp', '.gif', '.avif'];

export function scanAlbumPhotos(albumId: string): Photo[] {
  const albumPath = path.join(process.cwd(), GALLERY_DIR, albumId);

  if (!fs.existsSync(albumPath)) {
    return [];
  }

  const files = fs.readdirSync(albumPath);
  const photos: Photo[] = [];

  for (const file of files) {
    const ext = path.extname(file).toLowerCase();
    if (IMAGE_EXTENSIONS.includes(ext)) {
      photos.push({
        id: path.basename(file, ext),
        url: `/img/gallery/${albumId}/${file}`,
        filename: file,
      });
    }
  }

  // 按文件名排序
  return photos.sort((a, b) =>
    a.filename.localeCompare(b.filename, undefined, { numeric: true })
  );
}

自动发现相册

不仅照片可以自动扫描,相册本身也可以自动发现:

export function scanAllAlbums(): Album[] {
  const galleryPath = path.join(process.cwd(), GALLERY_DIR);

  if (!fs.existsSync(galleryPath)) {
    fs.mkdirSync(galleryPath, { recursive: true });
    return [];
  }

  const entries = fs.readdirSync(galleryPath, { withFileTypes: true });
  const albums: Album[] = [];

  for (const entry of entries) {
    if (entry.isDirectory()) {
      const albumId = entry.name;
      const photos = scanAlbumPhotos(albumId);

      if (photos.length > 0) {
        albums.push({
          id: albumId,
          title: albumId,           // 默认用文件夹名作为标题
          cover: photos[0].url,     // 第一张图作为封面
          photos,
        });
      }
    }
  }

  return albums;
}

可选的 YAML 配置

如果想自定义相册标题和描述,仍然可以在 YAML 中配置:

- id: "travel-2023"      # 对应文件夹名
  title: "旅行 2023"      # 自定义标题
  description: "探索世界的足迹"

代码会自动合并扫描结果和配置信息,配置优先级更高。

最终效果

现在的使用流程变得非常简单:

优化后的相册页

使用步骤

  1. public/img/gallery/ 下创建文件夹
  2. 把照片放进去
  3. 重启开发服务器或重新构建
  4. 完成!

支持的图片格式:jpg、jpeg、png、webp、gif、avif

自动处理

  • 照片按文件名排序(支持数字排序,如 1, 2, 10 而不是 1, 10, 2)
  • 第一张照片自动作为相册封面
  • 自动统计照片数量

小技巧

照片排序

如果想控制照片的显示顺序,可以用数字前缀命名:

01-风景.jpg
02-人物.jpg
03-美食.jpg

自定义封面

如果不想用第一张照片作为封面,可以在 YAML 中指定:

- id: "travel-2023"
  cover: "/img/cover/custom-cover.webp"  # 自定义封面

隐藏相册

如果某个文件夹不想显示为相册,可以用下划线开头命名:

public/img/gallery/
├── travel-2023/     # 会显示
├── _drafts/         # 不会显示(以下划线开头)

写在最后

这个优化虽然不大,但确实让日常使用方便了很多。

以前想加几张照片,还得打开编辑器、找到配置文件、手动添加路径。现在直接把照片拖进文件夹就完事了,符合直觉,零学习成本。

好的工具应该是无感的——你不需要思考怎么用,自然而然就会用。这次优化就是朝着这个方向迈进了一小步。

© 2024 - 2026 吕小布 @insist
Powered by theme astro-koharu · Inspired by Shoka