我们理解需求:在前台文章详情页中,点击图片可以弹出一个模态框(lightbox),能放大查看、缩小、关闭等。需要为 Ryblog 添加一个轻量级图片查看器。点击图片后出现的模态框需要有“放大/缩小”按钮,方便用户调整查看尺寸。我们需要在模态框上添加两个按钮:放大(Zoom In)和缩小(Zoom Out),控制图片的 transform: scale()。
我们可以在 article.php 中引入一个简单的 lightbox 库,比如 lightbox2 或 fancybox,或者自己实现一个简单的模态框。为了轻量化,我们可以使用纯 CSS + JavaScript 实现一个简单的图片点击放大功能。
方案:监听 .article-content img 的点击事件,创建模态框显示该图片,并支持关闭。
无需引入外部库,直接修改 assets/js/main.js 添加代码。
给出实现代码。
请在 assets/js/main.js 末尾粘贴以下完整代码:
// ========== 图片点击放大(支持拖拽和滚轮缩放) ========== (function() { let modal = null; let img = null; let transform = { scale: 1, translateX: 0, translateY: 0 }; let isDragging = false; let startX = 0, startY = 0; let lastTranslateX = 0, lastTranslateY = 0; function createModal() { if (modal) return; // 创建模态框背景 modal = document.createElement('div'); modal.id = 'imageModal'; modal.style.cssText = ` display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); z-index: 9999; overflow: hidden; `; // 图片容器(用于拖拽) const container = document.createElement('div'); container.style.cssText = ` width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; cursor: grab; `; container.id = 'imageModalContainer'; // 图片元素 img = document.createElement('img'); img.style.cssText = ` max-width: none; max-height: none; user-select: none; pointer-events: none; transition: transform 0.05s linear; `; // 工具栏 const toolbar = document.createElement('div'); toolbar.style.cssText = ` position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.6); color: white; padding: 8px 16px; border-radius: 30px; font-size: 14px; display: flex; gap: 12px; z-index: 10001; backdrop-filter: blur(5px); `; const zoomInBtn = document.createElement('button'); zoomInBtn.textContent = '+'; const zoomOutBtn = document.createElement('button'); zoomOutBtn.textContent = '-'; const resetBtn = document.createElement('button'); resetBtn.textContent = '重置'; const scaleText = document.createElement('span'); scaleText.textContent = '100%'; [zoomInBtn, zoomOutBtn, resetBtn].forEach(btn => { btn.style.cssText = 'background:transparent; border:none; color:white; font-size:18px; cursor:pointer; padding:0 8px;'; }); toolbar.appendChild(zoomOutBtn); toolbar.appendChild(scaleText); toolbar.appendChild(zoomInBtn); toolbar.appendChild(resetBtn); // 关闭按钮 const closeBtn = document.createElement('span'); closeBtn.innerHTML = '×'; closeBtn.style.cssText = ` position: absolute; top: 20px; right: 30px; font-size: 40px; color: white; cursor: pointer; z-index: 10001; font-weight: bold; `; container.appendChild(img); modal.appendChild(container); modal.appendChild(toolbar); modal.appendChild(closeBtn); document.body.appendChild(modal); // 事件绑定 closeBtn.onclick = closeModal; modal.onclick = (e) => { if (e.target === modal) closeModal(); }; // 滚轮缩放 container.addEventListener('wheel', (e) => { e.preventDefault(); const delta = e.deltaY > 0 ? -0.1 : 0.1; let newScale = transform.scale + delta; if (newScale < 0.5) newScale = 0.5; if (newScale > 3) newScale = 3; // 获取鼠标相对于图片的位置(简化:以图片中心为中心缩放) // 为了更好的体验,我们以鼠标位置为中心,但为简化,先以图片中心为中心 const rect = img.getBoundingClientRect(); const mouseX = e.clientX - rect.left; const mouseY = e.clientY - rect.top; const scaleRatio = newScale / transform.scale; transform.translateX = mouseX - (mouseX - transform.translateX) * scaleRatio; transform.translateY = mouseY - (mouseY - transform.translateY) * scaleRatio; transform.scale = newScale; applyTransform(); updateScaleText(scaleText); }); // 拖拽 container.addEventListener('mousedown', (e) => { if (e.button !== 0) return; isDragging = true; startX = e.clientX; startY = e.clientY; lastTranslateX = transform.translateX; lastTranslateY = transform.translateY; container.style.cursor = 'grabbing'; e.preventDefault(); }); window.addEventListener('mousemove', (e) => { if (!isDragging) return; const dx = e.clientX - startX; const dy = e.clientY - startY; transform.translateX = lastTranslateX + dx; transform.translateY = lastTranslateY + dy; applyTransform(); }); window.addEventListener('mouseup', () => { isDragging = false; container.style.cursor = 'grab'; }); // 按钮点击 zoomInBtn.onclick = () => { transform.scale = Math.min(3, transform.scale + 0.2); applyTransform(); updateScaleText(scaleText); }; zoomOutBtn.onclick = () => { transform.scale = Math.max(0.5, transform.scale - 0.2); applyTransform(); updateScaleText(scaleText); }; resetBtn.onclick = () => { transform = { scale: 1, translateX: 0, translateY: 0 }; applyTransform(); updateScaleText(scaleText); }; container.ondblclick = () => { transform = { scale: 1, translateX: 0, translateY: 0 }; applyTransform(); updateScaleText(scaleText); }; function applyTransform() { img.style.transform = `translate(${transform.translateX}px, ${transform.translateY}px) scale(${transform.scale})`; } function updateScaleText(span) { span.textContent = Math.round(transform.scale * 100) + '%'; } } function openModal(imageSrc) { createModal(); // 确保模态框存在 if (!img) return; img.src = imageSrc; transform = { scale: 1, translateX: 0, translateY: 0 }; applyTransform(); const scaleSpan = document.querySelector('#imageModal .toolbar-scale') || (() => { const span = document.createElement('span'); span.className = 'toolbar-scale'; return span; })(); updateScaleText(scaleSpan); modal.style.display = 'block'; document.body.style.overflow = 'hidden'; } function closeModal() { if (modal) modal.style.display = 'none'; if (img) img.src = ''; document.body.style.overflow = ''; } // 辅助函数 function applyTransform() { if (!img) return; img.style.transform = `translate(${transform.translateX}px, ${transform.translateY}px) scale(${transform.scale})`; } function updateScaleText(span) { if (span) span.textContent = Math.round(transform.scale * 100) + '%'; } // 绑定所有 .article-content 内的图片 function bindImageClick() { document.querySelectorAll('.article-content img').forEach(img => { if (img.hasAttribute('data-zoom-bound')) return; img.style.cursor = 'pointer'; img.addEventListener('click', (e) => { e.stopPropagation(); openModal(img.src); }); img.setAttribute('data-zoom-bound', 'true'); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', bindImageClick); } else { bindImageClick(); } // 监听动态内容 const observer = new MutationObserver(() => bindImageClick()); const targetNode = document.querySelector('.article-content'); if (targetNode) observer.observe(targetNode, { childList: true, subtree: true }); })();
功能说明
该功能能否通用?
回答:是的,该函数独立,只要页面有 .article-content img 且引入了 main.js 即可。对于 Ryweb1.0,直接复制到 main.js 末尾即可,无需额外修改。
这个图片点击放大功能是完全独立、零依赖的,不依赖于任何框架或特定的类名(除了 .article-content img 这个选择器)。因此,它可以应用到任何结构类似的网站中,只要将代码复制到您的 main.js 文件末尾即可。
对于 Ryweb 1.0 或者别的系统,操作步骤如下:
打开
/assets/js/main.js文件。将函数代码追加到文件末尾即可。
保存文件,清除浏览器缓存,刷新前台文章页。
为什么直接复制就能用?
代码自动查找页面中
.article-content img元素,这正是 Ryweb 1.0 文章内容区包裹图片的容器类。无需修改 HTML 或 PHP,完全由 JavaScript 驱动。
样式、事件、模态框全部在代码中动态创建,不会与现有样式冲突。
如果需要应用到其他网站,只需确保选择器匹配您网站文章内容区的图片容器。例如:
若您的文章内容区类名为
.post-content,则将代码中的'.article-content img'改为'.post-content img'即可。
现在您已经拥有了一个轻量、实用的图片放大预览功能,可以直接集成到您的系统中。
发表评论 (0)
留下你的足迹