Fancybox 灯箱替换 PhotoSwipe 指南
本文档详细说明如何将 Mizuki 主题中的 PhotoSwipe 灯箱替换为 Fancybox。
Fuck matsuzaka-yuki,谁教你这么写相册页面的
1. 当前 PhotoSwipe 实现分析
PhotoSwipe 的实现主要在以下文件中:
src/layouts/Layout.astro
- PhotoSwipe 初始化脚本src/styles/photoswipe.css
- PhotoSwipe 样式定制package.json
- PhotoSwipe 依赖
1.1 PhotoSwipe 初始化代码
在 src/layouts/Layout.astro
文件末尾,有以下 PhotoSwipe 初始化代码:
javascript
<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>
1.2 PhotoSwipe 样式文件
在 src/styles/photoswipe.css
文件中:
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;
}
2. 替换步骤
2.1 安装 Fancybox 依赖
您已经运行了 pnpm add @fancyapps/ui
,这会安装 Fancybox 所需的依赖。
2.2 修改 Layout.astro 文件
需要替换 PhotoSwipe 初始化代码为 Fancybox 初始化代码。
2.2.1 删除 PhotoSwipe 相关代码
删除 src/layouts/Layout.astro
文件末尾的整个 PhotoSwipe 脚本部分。
2.2.2 添加 Fancybox 初始化代码
在相同位置添加以下 Fancybox 初始化代码:
javascript
<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>
2.3 更新相册页面链接属性
需要更新相册页面中的图片链接属性,以支持 Fancybox 并避免默认跳转行为。
修改 src/pages/albums/[id]/index.astro
文件中的图片链接部分:
将原来的:
astro
<a
href={photo.src}
data-pswp-width={photo.width || 1200}
data-pswp-height={photo.height || 800}
target="_blank"
class="block"
>
替换为:
astro
<a
href="javascript:void(0)"
data-src={photo.src}
data-fancybox="gallery"
data-caption={photo.title || photo.alt}
class="block"
>
这样可以避免默认的链接跳转行为,同时让 Fancybox 正确显示图片。
2.4 添加 Fancybox 自定义样式(可选)
如果需要自定义 Fancybox 的外观,可以在 src/styles/
目录下创建一个新的 CSS 文件,例如 fancybox-custom.css
:
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
中导入这个样式文件:
astro
<link rel="stylesheet" href="/styles/fancybox-custom.css" />
3. Fancybox 配置选项
以下是一些常用的 Fancybox 配置选项:
3.1 基本配置
javascript
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",
},
});
3.2 高级配置
javascript
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",
},
});
4. 测试验证
完成上述更改后,请执行以下步骤验证替换是否成功:
- 运行开发服务器:
pnpm dev
- 访问相册页面,点击图片查看是否正常显示 Fancybox 灯箱
- 检查控制台是否有错误信息
- 测试不同设备上的显示效果
5. 注意事项
- 保留 PhotoSwipe 依赖包,按照您的要求不删除
- 确保 Fancybox 的 CSS 样式正确加载
- 如果遇到图片加载问题,检查图片路径是否正确
- 测试所有包含图片的页面,确保 Fancybox 正常工作
6. 故障排除
如果遇到问题,请检查以下几点:
- 确认
@fancyapps/ui
已正确安装 - 检查 Fancybox 初始化代码是否正确
- 确认图片链接包含正确的
data-fancybox
属性 - 查看浏览器控制台是否有错误信息