给博客加个图片灯箱

3 min
lightbox
lightbox

博客里的图片太小,看不清楚?加个灯箱功能,点击就能放大查看。

创建组件

src/components/ 目录下新建 ImageLightbox.astro 文件,复制下面的代码:

---
export interface Props {
	src: string;
	alt: string;
	caption?: string;
}

const { src, alt, caption } = Astro.props;
---

<div class="lightbox-container">
	<img 
		src={src} 
		alt={alt}
		class="lightbox-image"
		loading="lazy"
	/>
	{caption && <p class="image-caption">{caption}</p>}
</div>

<div id="lightbox-modal" class="lightbox-modal">
	<span class="close-lightbox">&times;</span>
	<img class="lightbox-content" id="lightbox-img" />
	{caption && <div id="lightbox-caption" class="lightbox-caption"></div>}
</div>

<script>
	document.addEventListener('DOMContentLoaded', () => {
		const modal = document.getElementById('lightbox-modal') as HTMLElement;
		const modalImg = document.getElementById('lightbox-img') as HTMLImageElement;
		const modalCaption = document.getElementById('lightbox-caption') as HTMLElement;
		const images = document.querySelectorAll('.lightbox-image') as NodeListOf<HTMLImageElement>;
		const closeBtn = document.querySelector('.close-lightbox') as HTMLElement;

		if (!modal || !modalImg || !closeBtn) {
			console.error('Lightbox: Required elements not found');
			return;
		}

		images.forEach(img => {
			img.addEventListener('click', () => {
				modal.style.display = 'block';
				modalImg.src = img.src;
				if (modalCaption) {
					const caption = img.nextElementSibling as HTMLElement;
					if (caption && caption.classList.contains('image-caption')) {
						modalCaption.textContent = caption.textContent || '';
						modalCaption.style.display = 'block';
					} else {
						modalCaption.style.display = 'none';
					}
				}
				document.body.style.overflow = 'hidden';
			});
		});

		closeBtn.addEventListener('click', () => {
			modal.style.display = 'none';
			document.body.style.overflow = 'auto';
		});

		modal.addEventListener('click', (e) => {
			if (e.target === modal) {
				modal.style.display = 'none';
				document.body.style.overflow = 'auto';
			}
		});

		document.addEventListener('keydown', (e) => {
			if (e.key === 'Escape' && modal.style.display === 'block') {
				modal.style.display = 'none';
				document.body.style.overflow = 'auto';
			}
		});
	});
</script>

<style>
	.lightbox-container {
		margin: 2rem 0;
		text-align: center;
	}

	.lightbox-image {
		max-width: 100%;
		height: auto;
		cursor: pointer;
		transition: transform 0.3s ease;
		border-radius: 4px;
		box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
	}

	.lightbox-image:hover {
		transform: scale(1.02);
	}

	.image-caption {
		margin-top: 0.8rem;
		font-size: 0.9rem;
		color: #666;
		font-style: italic;
	}

	.lightbox-modal {
		display: none;
		position: fixed;
		z-index: 1000;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		background-color: rgba(0, 0, 0, 0.9);
		backdrop-filter: blur(5px);
	}

	.lightbox-content {
		margin: auto;
		display: block;
		width: 80%;
		max-width: 900px;
		max-height: 90vh;
		object-fit: contain;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		border-radius: 4px;
	}

	.close-lightbox {
		position: absolute;
		top: 20px;
		right: 35px;
		color: #f1f1f1;
		font-size: 40px;
		font-weight: bold;
		transition: 0.3s;
		cursor: pointer;
		z-index: 1001;
	}

	.close-lightbox:hover {
		color: #bbb;
	}

	.lightbox-caption {
		margin: auto;
		display: block;
		width: 80%;
		max-width: 900px;
		text-align: center;
		color: #f1f1f1;
		padding: 10px 0;
		position: absolute;
		bottom: 20px;
		left: 50%;
		transform: translateX(-50%);
		font-size: 1rem;
	}

	@media only screen and (max-width: 768px) {
		.lightbox-content {
			width: 95%;
		}
		
		.lightbox-caption {
			width: 95%;
			font-size: 0.9rem;
			bottom: 10px;
		}
		
		.close-lightbox {
			top: 15px;
			right: 20px;
			font-size: 30px;
		}
	}
</style>

使用组件

在文章中导入并使用:

---
title: "我的文章"
---

import ImageLightbox from '../components/ImageLightbox.astro';

<ImageLightbox 
  src="/images/photo.jpg" 
  alt="图片说明" 
  caption="可选的标题"
/>

测试

启动开发服务器,访问页面,点击图片试试效果。

关闭方式:点击右上角 ×、点击背景、按 ESC 键。

常见问题

图片没反应? 检查组件路径和导入语句是否正确。

样式不对? 看看有没有全局样式覆盖,或者清除缓存试试。

想改样式? 直接修改 <style> 标签里的 CSS。

进阶

组件已经支持懒加载,提升页面速度。

想加过渡动画?在 .lightbox-modal 里加 animation: fadeIn 0.3s ease;

想支持滚轮缩放?在 <script> 里添加 wheel 事件监听。

最后

保存文件后记得重启开发服务器,多测试几次确保功能正常。