commit
f733212c4b
@ -1,5 +1,4 @@
|
||||
(function() {
|
||||
// 灯箱插件
|
||||
class Lightbox {
|
||||
constructor(options = {}) {
|
||||
this.options = Object.assign({
|
||||
@ -13,11 +12,11 @@
|
||||
this.images = [];
|
||||
this.currentIndex = 0;
|
||||
this.isOpen = false;
|
||||
this.isZoomed = false;
|
||||
this.zoomLevel = 1;
|
||||
this.touchStartX = 0;
|
||||
this.touchEndX = 0;
|
||||
this.wheelTimer = null;
|
||||
this.preloadedImages = {};
|
||||
|
||||
this.init();
|
||||
}
|
||||
@ -37,7 +36,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
background-color: transparent;
|
||||
backdrop-filter: blur(5px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -45,9 +44,11 @@
|
||||
opacity: 0;
|
||||
transition: opacity ${this.options.animationDuration}ms ease;
|
||||
pointer-events: none;
|
||||
z-index: 10000;
|
||||
}
|
||||
.lb-lightbox-overlay.active {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
.lb-lightbox-content-wrapper {
|
||||
position: relative;
|
||||
@ -58,103 +59,70 @@
|
||||
height: 100%;
|
||||
}
|
||||
.lb-lightbox-container {
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
transition: transform ${this.options.animationDuration}ms cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.lb-lightbox-image-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.lb-lightbox-image {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
transition: transform ${this.options.animationDuration}ms cubic-bezier(0.25, 0.1, 0.25, 1), opacity ${this.options.animationDuration}ms ease;
|
||||
opacity: 0;
|
||||
}
|
||||
.lb-lightbox-nav {
|
||||
.lb-lightbox-nav, .lb-lightbox-close {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
color: #333;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
font-size: 30px;
|
||||
z-index: 2;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.lb-lightbox-nav:hover {
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
transform: translateY(-50%) scale(1.1);
|
||||
}
|
||||
.lb-lightbox-nav:active {
|
||||
transform: translateY(-50%) scale(0.9);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.lb-lightbox-prev {
|
||||
left: 20px;
|
||||
top: calc(50% - 25px);
|
||||
}
|
||||
.lb-lightbox-next {
|
||||
right: 20px;
|
||||
top: calc(50% - 25px);
|
||||
}
|
||||
.lb-lightbox-close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
color: #333;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.lb-lightbox-close:hover {
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.lb-lightbox-close:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.lb-lightbox-nav {
|
||||
.lb-lightbox-nav, .lb-lightbox-close {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.lb-lightbox-close {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.lb-lightbox-overlay {
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
.lb-lightbox-nav,
|
||||
.lb-lightbox-close {
|
||||
background-color: rgba(50, 50, 50, 0.8);
|
||||
color: #fff;
|
||||
}
|
||||
.lb-lightbox-nav:hover,
|
||||
.lb-lightbox-close:hover {
|
||||
background-color: rgba(70, 70, 70, 1);
|
||||
}
|
||||
.lb-lightbox-image {
|
||||
box-shadow: 0 10px 30px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
@ -163,7 +131,6 @@
|
||||
createLightbox() {
|
||||
this.overlay = document.createElement('div');
|
||||
this.overlay.className = 'lb-lightbox-overlay';
|
||||
this.overlay.style.zIndex = '-1';
|
||||
|
||||
this.contentWrapper = document.createElement('div');
|
||||
this.contentWrapper.className = 'lb-lightbox-content-wrapper';
|
||||
@ -171,6 +138,9 @@
|
||||
this.container = document.createElement('div');
|
||||
this.container.className = 'lb-lightbox-container';
|
||||
|
||||
this.imageWrapper = document.createElement('div');
|
||||
this.imageWrapper.className = 'lb-lightbox-image-wrapper';
|
||||
|
||||
this.image = document.createElement('img');
|
||||
this.image.className = 'lb-lightbox-image';
|
||||
|
||||
@ -186,15 +156,17 @@
|
||||
this.closeButton.className = 'lb-lightbox-close';
|
||||
this.closeButton.innerHTML = '×';
|
||||
|
||||
this.container.appendChild(this.image);
|
||||
this.imageWrapper.appendChild(this.image);
|
||||
this.container.appendChild(this.imageWrapper);
|
||||
this.contentWrapper.appendChild(this.container);
|
||||
this.contentWrapper.appendChild(this.prevButton);
|
||||
this.contentWrapper.appendChild(this.nextButton);
|
||||
this.contentWrapper.appendChild(this.closeButton);
|
||||
|
||||
this.overlay.appendChild(this.contentWrapper);
|
||||
|
||||
document.body.appendChild(this.overlay);
|
||||
|
||||
this.closeButton.addEventListener('click', this.close.bind(this));
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
@ -215,7 +187,7 @@
|
||||
if (clickedImage && !this.isOpen) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.images = Array.from(document.querySelectorAll('.markdown-body img'));
|
||||
this.images = Array.from(document.querySelectorAll('.markdown-body img, table img'));
|
||||
this.currentIndex = this.images.indexOf(clickedImage);
|
||||
this.open();
|
||||
}
|
||||
@ -224,17 +196,11 @@
|
||||
handleOverlayClick(event) {
|
||||
if (event.target === this.overlay && this.options.closeOnOverlayClick) {
|
||||
this.close();
|
||||
} else if (!event.target.closest('.lb-lightbox-container')) {
|
||||
const elementBelow = document.elementFromPoint(event.clientX, event.clientY);
|
||||
if (elementBelow) {
|
||||
elementBelow.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown(event) {
|
||||
if (!this.isOpen) return;
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowLeft':
|
||||
this.showPreviousImage();
|
||||
@ -250,16 +216,22 @@
|
||||
|
||||
handleWheel(event) {
|
||||
event.preventDefault();
|
||||
clearTimeout(this.wheelTimer);
|
||||
|
||||
this.wheelTimer = setTimeout(() => {
|
||||
const delta = Math.sign(event.deltaY);
|
||||
if (delta > 0) {
|
||||
this.showNextImage();
|
||||
} else {
|
||||
this.showPreviousImage();
|
||||
}
|
||||
}, 50);
|
||||
if (event.ctrlKey) {
|
||||
this.zoomLevel += event.deltaY > 0 ? -0.1 : 0.1;
|
||||
this.zoomLevel = Math.max(1, this.zoomLevel);
|
||||
this.image.style.transform = `scale(${this.zoomLevel})`;
|
||||
} else {
|
||||
clearTimeout(this.wheelTimer);
|
||||
this.wheelTimer = setTimeout(() => {
|
||||
const delta = Math.sign(event.deltaY);
|
||||
if (delta > 0) {
|
||||
this.showNextImage();
|
||||
} else {
|
||||
this.showPreviousImage();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
handleTouchStart(event) {
|
||||
@ -273,20 +245,14 @@
|
||||
handleTouchEnd() {
|
||||
const difference = this.touchStartX - this.touchEndX;
|
||||
if (Math.abs(difference) > 50) {
|
||||
if (difference > 0) {
|
||||
this.showNextImage();
|
||||
} else {
|
||||
this.showPreviousImage();
|
||||
}
|
||||
difference > 0 ? this.showNextImage() : this.showPreviousImage();
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
this.isOpen = true;
|
||||
this.overlay.style.zIndex = '10000';
|
||||
this.overlay.classList.add('active');
|
||||
this.showImage();
|
||||
this.overlay.style.opacity = '1';
|
||||
this.showImage(this.images[this.currentIndex].src);
|
||||
document.body.style.overflow = 'hidden';
|
||||
if (typeof this.options.onOpen === 'function') {
|
||||
this.options.onOpen();
|
||||
@ -294,75 +260,97 @@
|
||||
}
|
||||
|
||||
close() {
|
||||
this.isOpen = false;
|
||||
this.overlay.style.opacity = '0';
|
||||
this.overlay.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
setTimeout(() => {
|
||||
this.image.style.transform = '';
|
||||
this.zoomLevel = 1;
|
||||
this.isZoomed = false;
|
||||
this.overlay.style.zIndex = '-1';
|
||||
}, this.options.animationDuration);
|
||||
this.overlay.classList.remove('active');
|
||||
this.isOpen = false;
|
||||
this.clearPreloadedImages();
|
||||
if (typeof this.options.onClose === 'function') {
|
||||
this.options.onClose();
|
||||
}
|
||||
this.unbindEvents();
|
||||
}
|
||||
|
||||
showPreviousImage() {
|
||||
if (this.currentIndex > 0) {
|
||||
this.currentIndex--;
|
||||
this.showImage();
|
||||
this.showImage(this.images[this.currentIndex].src);
|
||||
this.resetButtonScale(this.prevButton);
|
||||
}
|
||||
}
|
||||
|
||||
showNextImage() {
|
||||
if (this.currentIndex < this.images.length - 1) {
|
||||
this.currentIndex++;
|
||||
this.showImage();
|
||||
this.showImage(this.images[this.currentIndex].src);
|
||||
this.resetButtonScale(this.nextButton);
|
||||
}
|
||||
}
|
||||
|
||||
showImage() {
|
||||
const imgSrc = this.images[this.currentIndex].src;
|
||||
this.image.style.opacity = '0';
|
||||
resetButtonScale(button) {
|
||||
button.style.transform = 'scale(1.1)';
|
||||
setTimeout(() => {
|
||||
button.style.transform = 'scale(1)';
|
||||
}, 200);
|
||||
}
|
||||
|
||||
showImage(imgSrc) {
|
||||
const newImage = new Image();
|
||||
newImage.src = imgSrc;
|
||||
|
||||
newImage.onload = () => {
|
||||
this.image.style.transition = `opacity ${this.options.animationDuration}ms ease`;
|
||||
this.image.style.transform = 'scale(1)';
|
||||
this.image.src = imgSrc;
|
||||
this.image.style.opacity = '1';
|
||||
|
||||
this.preloadImages();
|
||||
this.prevButton.style.display = this.currentIndex === 0 ? 'none' : 'block';
|
||||
this.nextButton.style.display = this.currentIndex === this.images.length - 1 ? 'none' : 'block';
|
||||
};
|
||||
|
||||
this.prevButton.style.display = this.currentIndex > 0 ? '' : 'none';
|
||||
this.nextButton.style.display = this.currentIndex < this.images.length - 1 ? '' : 'none';
|
||||
|
||||
if (typeof this.options.onNavigate === 'function') {
|
||||
this.options.onNavigate(this.currentIndex);
|
||||
}
|
||||
|
||||
this.preloadImages();
|
||||
}
|
||||
|
||||
zoom(factor) {
|
||||
this.zoomLevel += factor;
|
||||
this.zoomLevel = Math.max(1, Math.min(this.zoomLevel, 3));
|
||||
this.image.style.transform = `scale(${this.zoomLevel})`;
|
||||
this.isZoomed = this.zoomLevel !== 1;
|
||||
newImage.onerror = () => {
|
||||
console.error('Failed to load image:', imgSrc);
|
||||
};
|
||||
}
|
||||
|
||||
preloadImages() {
|
||||
const preloadNext = (this.currentIndex + 1) % this.images.length;
|
||||
const preloadPrev = (this.currentIndex - 1 + this.images.length) % this.images.length;
|
||||
new Image().src = this.images[preloadNext].src;
|
||||
new Image().src = this.images[preloadPrev].src;
|
||||
const preloadNext = this.currentIndex + 1;
|
||||
const preloadPrev = this.currentIndex - 1;
|
||||
|
||||
if (preloadNext < this.images.length) {
|
||||
this.preloadedImages[preloadNext] = new Image();
|
||||
this.preloadedImages[preloadNext].src = this.images[preloadNext].src;
|
||||
}
|
||||
|
||||
if (preloadPrev >= 0) {
|
||||
this.preloadedImages[preloadPrev] = new Image();
|
||||
this.preloadedImages[preloadPrev].src = this.images[preloadPrev].src;
|
||||
}
|
||||
}
|
||||
|
||||
clearPreloadedImages() {
|
||||
Object.keys(this.preloadedImages).forEach(key => {
|
||||
this.preloadedImages[key].src = '';
|
||||
});
|
||||
this.preloadedImages = {};
|
||||
}
|
||||
|
||||
unbindEvents() {
|
||||
document.removeEventListener('click', this.handleImageClick.bind(this), true);
|
||||
this.overlay.removeEventListener('click', this.handleOverlayClick.bind(this));
|
||||
this.prevButton.removeEventListener('click', this.showPreviousImage.bind(this));
|
||||
this.nextButton.removeEventListener('click', this.showNextImage.bind(this));
|
||||
this.closeButton.removeEventListener('click', this.close.bind(this));
|
||||
document.removeEventListener('keydown', this.handleKeyDown.bind(this));
|
||||
this.overlay.removeEventListener('wheel', this.handleWheel.bind(this));
|
||||
this.overlay.removeEventListener('touchstart', this.handleTouchStart.bind(this));
|
||||
this.overlay.removeEventListener('touchmove', this.handleTouchMove.bind(this));
|
||||
this.overlay.removeEventListener('touchend', this.handleTouchEnd.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
// 将 Lightbox 类添加到全局对象
|
||||
window.Lightbox = Lightbox;
|
||||
|
||||
// 自动初始化
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new Lightbox();
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user