Skip to content

Fancybox

本文档详细说明如何将 Mizuki 主题中的 PhotoSwipe 灯箱替换为 Fancybox。

Fuck matsuzaka-yuki,谁教你这么写相册页面的

PhotoSwipe 的实现主要在以下文件中:

  1. src/layouts/Layout.astro - PhotoSwipe 初始化脚本
  2. src/styles/photoswipe.css - PhotoSwipe 样式定制
  3. package.json - PhotoSwipe 依赖

src/layouts/Layout.astro 文件末尾,有以下 PhotoSwipe 初始化代码:

<script>
import PhotoSwipeLightbox from "photoswipe/lightbox"
import "photoswipe/style.css"
let lightbox: PhotoSwipeLightbox
function createPhotoSwipe() {
lightbox = new PhotoSwipeLightbox({
gallery: ".custom-md img, #post-cover img, .moment-images img",
pswpModule: () => import("photoswipe"),
closeSVG: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M480-424 284-228q-11 11-28 11t-28-11q-11-11-11-28t11-28l196-196-196-196q-11-11-11-28t11-28q11-11 28-11t28 11l196 196 196-196q11-11 11-28t-11-28q-11-11-28-11t-28 11L480-424Z"/></svg>',
zoomSVG: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M340-540h-40q-17 0-28.5-11.5T260-580q0-17 11.5-28.5T300-620h40v-40q0-17 11.5-28.5T380-700q17 0 28.5 11.5T420-660v40h40q17 0 28.5 11.5T500-580q0 17-11.5 28.5T460-540h-40v40q0 17-11.5 28.5T380-460q-17 0-28.5-11.5T340-500v-40Zm0-80q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>',
padding: { top: 20, bottom: 20, left: 20, right: 20 },
wheelToZoom: true,
arrowPrev: false,
arrowNext: false,
imageClickAction: 'close',
tapAction: 'close',
doubleTapAction: 'zoom',
})
// Add filter BEFORE lightbox is initialized
lightbox.addFilter("domItemData", (itemData, element) => {
if (element instanceof HTMLImageElement) {
itemData.src = element.src
itemData.w = Number(element.naturalWidth || window.innerWidth)
itemData.h = Number(element.naturalHeight || window.innerHeight)
itemData.msrc = element.src
}
return itemData
})
// Initialize lightbox AFTER adding filters
lightbox.init()
}
const setup = () => {
if (!lightbox) {
createPhotoSwipe()
}
window.swup.hooks.on("page:view", () => {
createPhotoSwipe()
})
window.swup.hooks.on(
"content:replace",
() => {
lightbox?.destroy?.()
},
{ before: true },
)
}
if (window.swup) {
setup()
} else {
document.addEventListener("swup:enable", setup)
}
</script>

src/styles/photoswipe.css 文件中:

/* PhotoSwipe 按钮样式 */
.pswp__button {
@apply transition bg-black/40 hover:bg-black/50 active:bg-black/60 flex items-center justify-center mr-0 w-12 h-12 !important;
}
.pswp__button--zoom, .pswp__button--close {
@apply mt-4 rounded-xl active:scale-90 !important;
}
.pswp__button--zoom {
@apply mr-2.5 !important;
}
.pswp__button--close {
@apply mr-4 !important;
}

您已经运行了 pnpm add @fancyapps/ui,这会安装 Fancybox 所需的依赖。

需要替换 PhotoSwipe 初始化代码为 Fancybox 初始化代码。

删除 src/layouts/Layout.astro 文件末尾的整个 PhotoSwipe 脚本部分。

在相同位置添加以下 Fancybox 初始化代码:

<script>
import { Fancybox } from "@fancyapps/ui";
import "@fancyapps/ui/dist/fancybox/fancybox.css";
function initFancybox() {
// 销毁现有的 Fancybox 实例(如果存在)
Fancybox.close();
// 为相册图片添加 Fancybox 支持
Fancybox.bind(".custom-md img, #post-cover img, .moment-images img", {
groupAll: true,
Thumbs: {
autoStart: true,
showOnStart: "yes",
},
// 添加自定义按钮
Toolbar: {
display: {
left: ["infobar"],
middle: [
"zoomIn",
"zoomOut",
"toggle1to1",
"rotateCCW",
"rotateCW",
"flipX",
"flipY",
],
right: ["slideshow", "thumbs", "close"],
},
},
// 动画效果
animated: true,
// 是否支持拖拽
dragToClose: true,
// 是否支持键盘导航
keyboard: {
Escape: "close",
Delete: "close",
Backspace: "close",
PageUp: "next",
PageDown: "prev",
ArrowUp: "next",
ArrowDown: "prev",
ArrowRight: "next",
ArrowLeft: "prev",
},
// 自适应图片大小
fitToView: true,
// 图片预加载
preload: 3,
// 循环浏览
infinite: true,
// 智能图片适配
Panzoom: {
maxScale: 3,
minScale: 1,
},
// 幻灯片设置
Carousel: {
transition: "slide",
preload: 2,
},
});
// 为相册中的链接添加 Fancybox 支持
Fancybox.bind(".moment-images a[data-fancybox]", {
Thumbs: {
autoStart: true,
showOnStart: "yes",
},
// 工具栏配置
Toolbar: {
display: {
left: ["infobar"],
middle: [
"zoomIn",
"zoomOut",
"toggle1to1",
"rotateCCW",
"rotateCW",
"flipX",
"flipY",
],
right: ["slideshow", "thumbs", "close"],
},
},
// 动画效果
animated: true,
// 是否支持拖拽
dragToClose: true,
// 是否支持键盘导航
keyboard: {
Escape: "close",
Delete: "close",
Backspace: "close",
PageUp: "next",
PageDown: "prev",
ArrowUp: "next",
ArrowDown: "prev",
ArrowRight: "next",
ArrowLeft: "prev",
},
// 自适应图片大小
fitToView: true,
// 图片预加载
preload: 3,
// 循环浏览
infinite: true,
// 智能图片适配
Panzoom: {
maxScale: 3,
minScale: 1,
},
// 自定义源获取
source: (el) => {
return el.getAttribute("data-src") || el.getAttribute("href");
}
});
// 为单独的 fancybox 图片添加支持
Fancybox.bind("[data-fancybox]:not(.moment-images a)", {
// 自定义选项
Thumbs: {
autoStart: true,
showOnStart: "yes",
},
// 工具栏配置
Toolbar: {
display: {
left: ["infobar"],
middle: [
"zoomIn",
"zoomOut",
"toggle1to1",
"rotateCCW",
"rotateCW",
"flipX",
"flipY",
],
right: ["slideshow", "thumbs", "close"],
},
},
// 动画效果
animated: true,
// 是否支持拖拽
dragToClose: true,
// 是否支持键盘导航
keyboard: {
Escape: "close",
Delete: "close",
Backspace: "close",
PageUp: "next",
PageDown: "prev",
ArrowUp: "next",
ArrowDown: "prev",
ArrowRight: "next",
ArrowLeft: "prev",
},
// 自适应图片大小
fitToView: true,
// 图片预加载
preload: 3,
// 循环浏览
infinite: true,
// 智能图片适配
Panzoom: {
maxScale: 3,
minScale: 1,
},
});
}
const setup = () => {
// 初始化 Fancybox
initFancybox();
// 在页面视图更改时重新初始化
window.swup.hooks.on("page:view", () => {
// 等待 DOM 更新后初始化
setTimeout(() => {
initFancybox();
}, 100);
});
}
if (window.swup) {
setup()
} else {
document.addEventListener("swup:enable", setup)
// 如果 swup 尚未初始化,则直接初始化
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initFancybox);
} else {
initFancybox();
}
}
</script>

需要更新相册页面中的图片链接属性,以支持 Fancybox 并避免默认跳转行为。

修改 src/pages/albums/[id]/index.astro 文件中的图片链接部分:

将原来的:

<a
href={photo.src}
data-pswp-width={photo.width || 1200}
data-pswp-height={photo.height || 800}
target="_blank"
class="block"
>

替换为:

<a
href="javascript:void(0)"
data-src={photo.src}
data-fancybox="gallery"
data-caption={photo.title || photo.alt}
class="block"
>

这样可以避免默认的链接跳转行为,同时让 Fancybox 正确显示图片。

2.4 添加 Fancybox 自定义样式(可选)

Section titled “2.4 添加 Fancybox 自定义样式(可选)”

如果需要自定义 Fancybox 的外观,可以在 src/styles/ 目录下创建一个新的 CSS 文件,例如 fancybox-custom.css

/* Fancybox 自定义样式 */
.fancybox__container {
--fancybox-bg: rgba(0, 0, 0, 0.9);
--fancybox-thumbs-width: 64px;
--fancybox-thumbs-ratio: 1;
--fancybox-thumbs-border-radius: 4px;
}
.fancybox__toolbar {
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7), transparent);
padding: 8px;
backdrop-filter: blur(4px);
}
.fancybox__caption {
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
color: white;
font-size: 1rem;
padding: 1rem;
text-align: center;
backdrop-filter: blur(4px);
border-radius: 8px;
margin: 0 1rem 1rem 1rem;
}
.fancybox__nav {
--carousel-button-svg-width: 24px;
--carousel-button-svg-height: 24px;
}
.fancybox__thumbs {
background: rgba(0, 0, 0, 0.7);
padding: 2px;
border-radius: 8px;
backdrop-filter: blur(4px);
}
.fancybox__thumb {
border-radius: 4px;
overflow: hidden;
border: 2px solid transparent;
transition: all 0.2s ease;
}
.fancybox__thumb.is-loading {
background: rgba(255, 255, 255, 0.1);
}
.fancybox__thumb:hover {
border-color: rgba(255, 255, 255, 0.5);
transform: scale(1.05);
}
.fancybox__thumb.is-active {
border-color: #fff;
}
/* 按钮样式 */
.fancybox__button {
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
width: 44px;
height: 44px;
transition: all 0.2s ease;
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.fancybox__button:hover {
background: rgba(0, 0, 0, 0.7);
transform: scale(1.1);
border-color: rgba(255, 255, 255, 0.3);
}
.fancybox__button svg {
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
.fancybox__infobar {
color: white;
font-size: 0.9rem;
padding: 0 8px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.fancybox__toolbar {
padding: 4px;
}
.fancybox__button {
width: 36px;
height: 36px;
}
.fancybox__caption {
font-size: 0.9rem;
padding: 0.5rem;
margin: 0 0.5rem 0.5rem 0.5rem;
}
.fancybox__thumbs {
--fancybox-thumbs-width: 48px;
}
}
@media (max-width: 480px) {
.fancybox__button {
width: 32px;
height: 32px;
}
.fancybox__caption {
font-size: 0.8rem;
padding: 0.4rem;
}
.fancybox__thumbs {
--fancybox-thumbs-width: 40px;
}
}

然后在 src/layouts/Layout.astro 中导入这个样式文件:

<link rel="stylesheet" href="/styles/fancybox-custom.css" />

以下是一些常用的 Fancybox 配置选项:

Fancybox.bind("[data-fancybox]", {
// 启动时显示缩略图
Thumbs: {
autoStart: true,
showOnStart: "yes",
},
// 工具栏配置
Toolbar: {
display: {
left: ["infobar"],
middle: [
"zoomIn",
"zoomOut",
"toggle1to1",
"rotateCCW",
"rotateCW",
"flipX",
"flipY",
],
right: ["slideshow", "thumbs", "close"],
},
},
// 动画效果
animated: true,
// 是否支持拖拽
dragToClose: true,
// 是否支持键盘导航
keyboard: {
Escape: "close",
Delete: "close",
Backspace: "close",
PageUp: "next",
PageDown: "prev",
ArrowUp: "next",
ArrowDown: "prev",
ArrowRight: "next",
ArrowLeft: "prev",
},
});
Fancybox.bind("[data-fancybox]", {
// 自适应图片大小
fitToView: true,
// 图片预加载
preload: 3,
// 循环浏览
infinite: true,
// 幻灯片播放间隔(毫秒)
slideshow: {
autoplay: false,
delay: 3000,
},
// 缩放选项
Panzoom: {
maxScale: 3,
minScale: 1,
},
// 幻灯片设置
Carousel: {
transition: "slide",
preload: 2,
},
// 移动端优化
mobile: {
click: "close",
tap: "close",
doubleTap: "zoom",
},
});

完成上述更改后,请执行以下步骤验证替换是否成功:

  1. 运行开发服务器:pnpm dev
  2. 访问相册页面,点击图片查看是否正常显示 Fancybox 灯箱
  3. 检查控制台是否有错误信息
  4. 测试不同设备上的显示效果
  1. 保留 PhotoSwipe 依赖包,按照您的要求不删除
  2. 确保 Fancybox 的 CSS 样式正确加载
  3. 如果遇到图片加载问题,检查图片路径是否正确
  4. 测试所有包含图片的页面,确保 Fancybox 正常工作

如果遇到问题,请检查以下几点:

  1. 确认 @fancyapps/ui 已正确安装
  2. 检查 Fancybox 初始化代码是否正确
  3. 确认图片链接包含正确的 data-fancybox 属性
  4. 查看浏览器控制台是否有错误信息