/* lightbox.js — 图片查看器:缩放、拖拽、键盘操作 */ (function() { function openLightbox(src, alt) { var existing = document.querySelector('.lightbox-overlay'); if (existing) existing.remove(); var overlay = document.createElement('div'); overlay.className = 'lightbox-overlay'; var img = document.createElement('img'); img.src = src; img.alt = alt || ''; img.draggable = false; // 工具栏 var toolbar = document.createElement('div'); toolbar.className = 'lightbox-toolbar'; toolbar.innerHTML = '' + '' + '' + '' + ''; overlay.appendChild(img); overlay.appendChild(toolbar); document.body.appendChild(overlay); // 视图状态 var scale = 1, tx = 0, ty = 0; var baseW = 0, baseH = 0; var dragging = false, dragStartX = 0, dragStartY = 0, startTx = 0, startTy = 0; function apply() { img.style.transform = 'translate(' + tx + 'px,' + ty + 'px) scale(' + scale + ')'; } function fitToScreen() { if (!baseW) return; var sw = window.innerWidth, sh = window.innerHeight; scale = Math.min(sw * 0.9 / baseW, sh * 0.9 / baseH, 1); tx = (sw - baseW * scale) / 2; ty = (sh - baseH * scale) / 2; apply(); } function resetOrigin() { scale = 1; tx = (window.innerWidth - baseW) / 2; ty = (window.innerHeight - baseH) / 2; apply(); } function zoomAt(factor, cx, cy) { var newScale = Math.max(0.1, Math.min(scale * factor, 20)); tx = cx - (cx - tx) * (newScale / scale); ty = cy - (cy - ty) * (newScale / scale); scale = newScale; apply(); } function zoomCenter(factor) { var cx = window.innerWidth / 2; var cy = window.innerHeight / 2; var newScale = Math.max(0.1, Math.min(scale * factor, 20)); tx = cx - (cx - tx) * (newScale / scale); ty = cy - (cy - ty) * (newScale / scale); scale = newScale; apply(); } // 图片加载后初始化 img.onload = function() { baseW = img.naturalWidth; baseH = img.naturalHeight; fitToScreen(); }; // 如果已缓存 if (img.complete && img.naturalWidth) { baseW = img.naturalWidth; baseH = img.naturalHeight; fitToScreen(); } // 工具栏按钮(缩小 / 放大 / 适合 / 原始 / 关闭) var btns = toolbar.querySelectorAll('button'); btns[0].onclick = function(e) { e.stopPropagation(); zoomCenter(0.7); }; btns[1].onclick = function(e) { e.stopPropagation(); zoomCenter(1.4); }; btns[2].onclick = function(e) { e.stopPropagation(); fitToScreen(); }; btns[3].onclick = function(e) { e.stopPropagation(); resetOrigin(); }; btns[4].onclick = function(e) { e.stopPropagation(); close(); }; // 滚轮缩放(以鼠标为中心) overlay.addEventListener('wheel', function(e) { e.preventDefault(); var factor = e.deltaY < 0 ? 1.15 : 0.87; var rect = overlay.getBoundingClientRect(); var cx = e.clientX - rect.left; var cy = e.clientY - rect.top; var newScale = Math.max(0.1, Math.min(scale * factor, 20)); tx = cx - (cx - tx) * (newScale / scale); ty = cy - (cy - ty) * (newScale / scale); scale = newScale; apply(); }, { passive: false }); // 拖拽平移 overlay.addEventListener('pointerdown', function(e) { if (e.target.closest('.lightbox-toolbar')) return; dragging = true; dragStartX = e.clientX; dragStartY = e.clientY; startTx = tx; startTy = ty; img.classList.add('dragging'); overlay.setPointerCapture(e.pointerId); }); overlay.addEventListener('pointermove', function(e) { if (!dragging) return; tx = startTx + (e.clientX - dragStartX); ty = startTy + (e.clientY - dragStartY); apply(); }); overlay.addEventListener('pointerup', function() { dragging = false; img.classList.remove('dragging'); }); // ESC 关闭 function onKey(e) { if (e.key === 'Escape') { close(); } else if (e.key === '+' || e.key === '=') { zoomCenter(1.4); } else if (e.key === '-') { zoomCenter(0.7); } else if (e.key === '0') { fitToScreen(); } } function close() { overlay.remove(); document.removeEventListener('keydown', onKey); } document.addEventListener('keydown', onKey); // 激活动画 requestAnimationFrame(function() { overlay.classList.add('active'); }); } document.addEventListener('click', function(e) { var img = e.target; if (img.tagName !== 'IMG') return; if (!img.closest('.inline-figure') && !img.closest('.gallery-item')) return; if (img.closest('.lightbox-overlay')) return; e.preventDefault(); openLightbox(img.src, img.alt); }); })();