跳至正文
Yukihime

图片、视频与文章资源处理

图片、视频与文章资源处理

说明 AstroBlog 的文章图片解析、Astro 优化、R2 视频和文章列表瀑布流实现。

AstroBlog 中至少存在三类资源:src/ 下可以被 Astro 处理的本地图片,public/ 下按原路径输出的静态文件,以及远程 URL 或 R2 上的媒体。文章封面、正文插图和首页 Hero 视频的加载方式不同,不能用一个组件把它们全部当成普通字符串。

本地图片和远程图片

src/utils/image-utils.ts 和 src/utils/local-image.ts 负责判断图片来源、解析本地资源和选择质量。src/components/common/CoverImage.astro 处理文章卡片与 Hero 封面;放在 src/ 的图片可以进入 Astro 的响应式优化,public/ 图片则直接由 URL 引用,不会被构建器转换。

文章正文的相对图片路径还需要知道文章文件所在目录。src/plugins/article-images/source-resolver.mjs 和 index.mjs 在 Markdown/MDX 处理阶段解析相对路径、图注、宽图和灯箱属性。这个步骤必须发生在正文渲染前,否则路径会相对于网站根目录解析,开发环境能显示、生产环境却 404。

正文图片和卡片封面不能共用裁剪规则。卡片可以使用固定比例来维持网格高度,正文图片必须保留原始比例,避免图表、代码截图和授权信息被裁掉。图片组件还要输出 alt、figcaption 和必要的授权信息。

首页视频和 R2

首页 Hero 视频由 HomeVideoLayer.astro 负责渲染,生产媒体域名为 media.yukihime.dev。站点配置保存候选视频和当前选择,Layout.astro 只在首页添加 preconnect 和 DNS 预解析。视频节点带有候选数据属性,浏览器脚本根据设备和壁纸状态选择实际源。

视频不应该成为首页内容的唯一载体。标题、导航、文章入口和按钮都由 HTML 输出,视频加载失败时仍有完整的页面结构。百叶窗覆盖主视觉或用户关闭动态壁纸时,脚本会暂停视频;切换页面或替换视频节点时,需要清理旧的 play()、loadeddata 和 visibility 监听。

文章列表瀑布流

网格布局使用 PostPage.astro 的客户端脚本,而不是额外引入 Masonry 框架。脚本读取容器宽度、列数和卡片实际高度,将每张 .post-card-item 放入当前最短的列:

JavaScript
const itemWidth = (containerWidth - (colCount - 1) * gap) / colCount;
const colHeights = new Array(colCount).fill(0);

for (const item of items) {
  // 每次放入当前最短列,避免普通 CSS Grid 留下纵向空洞。
  const colIndex = colHeights.indexOf(Math.min(...colHeights));
  const top = colHeights[colIndex];
  item.style.position = "absolute";
  item.style.width = `${itemWidth}px`;
  item.style.top = `${top}px`;
  item.style.left = `${colIndex * (itemWidth + gap)}px`;
  // 记录该列下一张卡片可使用的顶部偏移。
  colHeights[colIndex] += item.offsetHeight + gap;
}

实际代码还处理双侧栏时的列数、窄屏强制列表模式、图片加载后的重排、coverVisibilityChange、自定义布局切换事件和 astro:before-swap 清理。因为卡片高度依赖图片,初始化时必须等待未完成图片的 load 事件;否则容器高度会按占位高度计算,图片加载后卡片互相覆盖。

性能边界

封面前两张使用 eager,其他文章使用 lazy;视频通过独立媒体域名和预连接减少握手时间;字体文件禁止内联进 CSS,避免 CJK 字体分片让首屏样式膨胀;生产构建使用 Terser、CSS 分割和资源压缩。图片质量由 siteConfig.imageOptimization 控制,当前格式为 WebP、质量 85。

性能优化还要检查桌面网络加载、文章正文图片清晰度、视频暂停是否生效、瀑布流重排是否造成布局跳动,以及 Pagefind 是否仍然能从最终 HTML 读取文章正文。

资源修改入口

修改文章图片解析:查 src/plugins/article-images/;修改封面显示:查 CoverImage.astro 和 PostCard.astro;修改图片质量或格式:查 siteConfig.imageOptimization 和 image-utils.ts;修改首页视频:查 HomeVideoLayer.astro、壁纸配置和 verify-home-wallpaper;修改瀑布流:查 PostPage.astro 的初始化、重排和清理函数。

powershell
# 先生成当前产物,再验证文章图片与浏览器行为。
pnpm build
# 使用 Chrome/Chromium 验证正文图片、figure 和 PhotoSwipe 灯箱。
pnpm verify:article-images
# 验证首页视频候选、播放节点和壁纸模式。
pnpm verify:home-wallpaper
# 输出构建资源和关键 bundle 的性能审计结果。
pnpm audit:performance

资源路径是构建契约的一部分。不要为了让本地图片显示而把路径硬编码成开发服务器地址,也不要在组件中绕过 Astro 的图片处理器直接读取源文件绝对路径。

正文图片插件的处理顺序

文章图片插件先识别 Markdown/HTML 中的图片节点,再根据文章 entry 的源文件目录解析相对路径。解析成功后生成带尺寸、alt、图注和灯箱数据的 figure 结构;远程 URL 保留为外链,不尝试读取远程文件;路径不存在时应在构建阶段报告错误或保留可诊断的原始 URL,而不是静默替换成首页封面。

文章图片与封面图片使用不同的缓存和尺寸策略。封面通常需要固定宽度和响应式 srcset,正文图更关注原比例和长图加载。新增图片属性时要检查 Markdown transformer、ArticleContent.astro、灯箱脚本、Pagefind 忽略范围和无障碍 alt 文本。

瀑布流的布局时序

瀑布流计算依赖三次状态:容器宽度确定、卡片 DOM 挂载、图片尺寸确定。PostPage.astro 先在页面切换后延迟初始化,再为未完成图片注册 load 监听;每次重排先清除旧的 inline position/width/top/left,再计算新列。修改卡片内部字体、摘要行数或封面比例,都可能改变高度,因此必须重新检查 resize 和 coverVisibilityChange。

资源目录和后台上传

后台媒体管理区区分 public/assets/images 和 src/assets/images。前者适合需要稳定 URL 或由外部配置直接引用的文件,后者适合需要 Astro 优化的组件资源。上传时 MediaManager.svelte 和 GitHub Proxy 会限制目标目录与扩展名;移动文件后还要全局搜索旧 URL,避免内容 Frontmatter 继续引用已删除资源。

文章图片灯箱由 ArticleImageLightbox.astro 使用 PhotoSwipe 管理,随独立阅读文档加载;普通共享 Markdown 仍使用原有图片行为。文章配色固定白色,字体与几何复用共享角色,不能把灯箱样式改动扩散到关于等页面。

视频资源不应进入 Git 仓库的大型历史。生产 Hero 视频放在 R2/媒体域名,仓库只保存候选地址和播放策略。替换视频时检查 HTTP Range、Content-Type、桌面浏览器自动播放与暂停状态、poster 及离开首页后的清理。本站保留非桌面访问限制,不增加手机或平板验收。

[ 公告 ]

如果你喜欢,那么欢迎来到我的世界!

了解更多
[ 音乐 ]
封面

音乐

找不到相关结果。
[ 全部文章 ]