以下是纯前端实现的方案,只需在页面底部添加以下 JavaScript 代码即可实现多图浏览功能:
<script>
// 全屏图库样式(动态注入)
const galleryStyle = document.createElement('style');
galleryStyle.textContent = `
.gallery-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.95);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
cursor: zoom-out;
}
.gallery-image {
max-width: 90vw;
max-height: 90vh;
object-fit: contain;
transition: opacity 0.3s;
}
.gallery-nav {
position: fixed;
top: 50%;
transform: translateY(-50%);
width: 40px;
height: 40px;
background: rgba(255,255,255,0.8);
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
.gallery-prev { left: 20px; }
.gallery-next { right: 20px; }
.gallery-counter {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 14px;
}
`;
document.head.appendChild(galleryStyle);
class ImageViewer {
constructor() {
this.images = [];
this.currentIndex = 0;
this.initGallery();
}
initGallery() {
// 获取文章内所有图片
const article = document.querySelector('#article-container');
this.images = Array.from(article.querySelectorAll('img[data-src]'));
// 添加点击事件
this.images.forEach((img, index) => {
img.dataset.index = index;
img.style.cursor = 'zoom-in';
img.addEventListener('click', (e) => this.open(e.target));
});
}
open(targetImg) {
this.currentIndex = parseInt(targetImg.dataset.index);
this.createOverlay();
this.showImage();
this.bindEvents();
}
createOverlay() {
this.overlay = document.createElement('div');
this.overlay.className = 'gallery-overlay';
this.imageEl = document.createElement('img');
this.imageEl.className = 'gallery-image';
this.prevBtn = this.createButton('❮', 'gallery-prev');
this.nextBtn = this.createButton('❯', 'gallery-next');
this.counter = this.createCounter();
this.overlay.append(this.prevBtn, this.imageEl, this.nextBtn, this.counter);
document.body.appendChild(this.overlay);
document.body.style.overflow = 'hidden';
}
createButton(text, className) {
const btn = document.createElement('div');
btn.className = `gallery-nav ${className}`;
btn.textContent = text;
return btn;
}
createCounter() {
const counter = document.createElement('div');
counter.className = 'gallery-counter';
return counter;
}
showImage() {
this.imageEl.src = this.images[this.currentIndex].dataset.src;
this.counter.textContent = `${this.currentIndex + 1} / ${this.images.length}`;
this.toggleNavButtons();
}
toggleNavButtons() {
this.prevBtn.style.display = this.currentIndex > 0 ? 'flex' : 'none';
this.nextBtn.style.display = this.currentIndex < this.images.length - 1 ? 'flex' : 'none';
}
bindEvents() {
// 按钮点击
this.prevBtn.addEventListener('click', () => this.navigate(-1));
this.nextBtn.addEventListener('click', () => this.navigate(1));
// 遮罩点击
this.overlay.addEventListener('click', (e) => {
if (e.target === this.overlay) this.close();
});
// 键盘事件
this.keyHandler = (e) => {
switch(e.key) {
case 'ArrowLeft': this.navigate(-1); break;
case 'ArrowRight': this.navigate(1); break;
case 'Escape': this.close(); break;
}
};
document.addEventListener('keydown', this.keyHandler);
// 触摸事件
this.touchStartX = 0;
this.overlay.addEventListener('touchstart', (e) => {
this.touchStartX = e.touches[0].clientX;
});
this.overlay.addEventListener('touchend', (e) => {
const deltaX = e.changedTouches[0].clientX - this.touchStartX;
if (Math.abs(deltaX) > 50) {
this.navigate(deltaX > 0 ? -1 : 1);
}
});
}
navigate(offset) {
this.currentIndex += offset;
if (this.currentIndex < 0) this.currentIndex = this.images.length - 1;
if (this.currentIndex >= this.images.length) this.currentIndex = 0;
this.showImage();
}
close() {
document.body.removeChild(this.overlay);
document.body.style.overflow = '';
document.removeEventListener('keydown', this.keyHandler);
}
}
// 初始化图库
document.addEventListener('DOMContentLoaded', () => {
new ImageViewer();
});
</script>
实现特点:
- 纯前端实现:无需修改后端代码,只需添加 JS 即可
- 自动绑定事件:
- 自动查找 #article-container 内的所有懒加载图片
- 自动添加点击事件和光标样式
- 交互功能:
- 左右箭头按钮导航
- 键盘方向键控制(← → ESC)
- 移动端触摸滑动切换
- 图片计数器显示
- 性能优化:
- 使用原生懒加载图片地址(data-src)
- 自动处理边界循环
- 动态创建/销毁 DOM 元素
- 样式隔离:
- 动态注入 CSS 样式
- 使用高 z-index 确保覆盖层级
- 响应式图片显示
使用说明:
- 点击任意图片进入全屏模式
- 支持以下操作:
- 点击左右箭头切换
- 使用键盘方向键切换
- 移动端左右滑动切换
- 点击背景/按 ESC 键退出
- 左上角显示当前图片位置 (X/Y)
注意事项:
- 确保图片父容器 ID 为
#article-container
- 依赖图片的
data-src
属性获取原图地址 - 自动忽略已加载的
src
占位图 - 与现有懒加载库兼容(只需保持
data-src
属性)
如果需要添加加载动画,可以在 showImage()
方法中添加以下代码:
// 在 showImage() 开头添加
this.imageEl.style.opacity = 0;
const loader = document.createElement('div');
loader.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
width: 30px;
height: 30px;
border: 3px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s linear infinite;
`;
this.overlay.appendChild(loader);
// 在图片加载完成后
this.imageEl.onload = () => {
this.imageEl.style.opacity = 1;
loader.remove();
};
// 在样式表中添加
@keyframes spin {
to { transform: rotate(360deg); }
}