本地HTML/JS实时图片画廊:监控文件夹实现增删改及点击放大
本地实时监控文件夹的图片画廊解决方案
你的需求
- 新增图片自动加入画廊
- 删除图片自动从画廊移除
- 修改图片自动刷新对应内容
- 点击图片从原位置放大至全屏(不用整页刷新)
现有代码的问题
- 图片刷新逻辑错误:
refresh函数接收的是getElementsByClassName返回的元素集合,但直接操作node.src——集合没有src属性,导致刷新完全失效。 - 无法感知文件变化:靠递增数字加载
test-n.jpg的方式,只能加载连续命名的图片,文件夹里的新增/删除操作根本检测不到。 - 无图片状态维护:没记录当前画廊的图片列表,没法对比文件变化来新增或移除元素。
完整解决方案(前端+轻量后端)
因为浏览器出于安全限制,不让前端直接读取本地文件夹的变化,所以需要搭个轻量后端配合,用Node.js实现就行,步骤简单不用复杂配置。
步骤1:准备环境
- 先装Node.js,官网下载后一路下一步安装即可
- 在你的画廊文件夹下,新建
server.js和package.json两个文件
步骤2:后端代码(server.js)
const http = require('http'); const fs = require('fs'); const path = require('path'); const chokidar = require('chokidar'); const WebSocket = require('ws'); // 图片文件夹路径,对应你原来的imgportfolio const imgDir = path.join(__dirname, 'imgportfolio'); // 允许的图片格式,可按需添加 const imgExts = ['.jpg', '.jpeg', '.png', '.gif']; // 创建静态文件服务器,托管HTML/CSS/图片等 const server = http.createServer((req, res) => { let filePath = req.url === '/' ? '/index.html' : req.url; filePath = path.join(__dirname, filePath); const ext = path.extname(filePath); let contentType = 'text/html'; if (ext === '.css') contentType = 'text/css'; if (ext === '.js') contentType = 'application/javascript'; if (imgExts.includes(ext)) contentType = `image/${ext.slice(1)}`; fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(404); res.end('文件不存在'); return; } res.writeHead(200, { 'Content-Type': contentType }); res.end(data); }); }); // 创建WebSocket服务,用来给前端推送文件变化 const wss = new WebSocket.Server({ server }); // 获取当前文件夹里的所有图片 function getImgList() { return fs.readdirSync(imgDir) .filter(file => imgExts.includes(path.extname(file).toLowerCase())) .map(file => `/imgportfolio/${file}`); } // 监听图片文件夹的变化 const watcher = chokidar.watch(imgDir, { ignoreInitial: false }); let currentImgList = getImgList(); watcher.on('all', (event, path) => { const newImgList = getImgList(); // 把最新图片列表推送给所有打开页面的客户端 wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ imgList: newImgList })); } }); currentImgList = newImgList; }); // 启动服务器,端口设为3000 const PORT = 3000; server.listen(PORT, () => { console.log(`服务器跑起来了,访问 http://localhost:${PORT}`); });
步骤3:package.json(用来安装依赖)
{ "name": "local-gallery", "version": "1.0.0", "dependencies": { "chokidar": "^3.5.3", "ws": "^8.14.2" } }
步骤4:前端代码(index.html)
<!doctype html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>实时图片画廊</title> <style> /* 基础画廊样式,可按你的需求修改 */ .row { display: flex; flex-wrap: wrap; gap: 10px; padding: 20px; } .gallery-item { flex: 1 1 calc(25% - 10px); min-width: 200px; cursor: zoom-in; } .gallery-img img { width: 100%; height: auto; display: block; transition: transform 0.2s; } .gallery-img img:hover { transform: scale(1.02); } /* 全屏放大的弹窗样式 */ .lightbox { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); display: none; align-items: center; justify-content: center; z-index: 9999; cursor: zoom-out; } .lightbox.active { display: flex; } .lightbox img { max-width: 90%; max-height: 90%; transition: transform 0.3s ease; } </style> </head> <body> <div class="ajax-inserted-content"> <section class="section gallery grid layout-4-col"> <div class="container"> <div class="row" id='gallery-items'></div> </div> </section> </div> <!-- 全屏放大的弹窗容器 --> <div class="lightbox" id="lightbox"> <img id="lightbox-img" src="" alt=""> </div> <script> const galleryContainer = document.getElementById('gallery-items'); const lightbox = document.getElementById('lightbox'); const lightboxImg = document.getElementById('lightbox-img'); let currentImgList = []; // 渲染画廊:对比新旧列表,新增/移除图片元素 function renderGallery(imgList) { // 先删掉画廊里已经不存在的图片 const existingImgs = Array.from(galleryContainer.querySelectorAll('.gallery-item img')); existingImgs.forEach(img => { const imgPath = img.src.split(window.location.origin)[1]; if (!imgList.includes(imgPath)) { img.closest('.gallery-item').parentElement.remove(); } }); // 添加新出现的图片 imgList.forEach(imgUrl => { if (!currentImgList.includes(imgUrl)) { const colDiv = document.createElement('div'); colDiv.className = 'col-3 col-lg-4 col-md-6 col-sm-12'; colDiv.innerHTML = ` <div class="gallery-item"> <div class="gallery-img"> <img class="img" src="${imgUrl}?t=${Date.now()}" alt="画廊图片"> </div> </div> `; galleryContainer.appendChild(colDiv); // 绑定点击放大事件,实现从原位置放大的效果 const img = colDiv.querySelector('img'); img.addEventListener('click', () => { lightboxImg.src = img.src.split('?')[0]; // 获取原图位置,设置初始缩放和位移 const rect = img.getBoundingClientRect(); const scale = rect.width / lightboxImg.offsetWidth; lightboxImg.style.transform = `translate(${rect.left}px, ${rect.top}px) scale(${scale})`; lightbox.classList.add('active'); // 延迟触发过渡动画 setTimeout(() => { lightboxImg.style.transform = 'translate(0,0) scale(1)'; }, 10); }); } }); // 更新当前图片列表 currentImgList = [...imgList]; } // 关闭全屏弹窗时的动画 lightbox.addEventListener('click', () => { const activeImg = galleryContainer.querySelector(`img[src^="${lightboxImg.src}"]`); if (activeImg) { const rect = activeImg.getBoundingClientRect(); const scale = rect.width / lightboxImg.offsetWidth; lightboxImg.style.transform = `translate(${rect.left}px, ${rect.top}px) scale(${scale})`; setTimeout(() => { lightbox.classList.remove('active'); lightboxImg.style.transform = ''; }, 300); } else { lightbox.classList.remove('active'); } }); // 连接WebSocket,接收后端推送的图片变化 const ws = new WebSocket(`ws://${window.location.host}`); ws.onmessage = (event) => { const data = JSON.parse(event.data); renderGallery(data.imgList); }; // 定时刷新图片,解决修改后浏览器缓存的问题 setInterval(() => { const imgs = galleryContainer.querySelectorAll('.img'); imgs.forEach(img => { const srcWithoutTimestamp = img.src.split('?')[0]; img.src = `${srcWithoutTimestamp}?t=${Date.now()}`; }); }, 2000); // 每2秒检查一次图片是否更新 </script> </body> </html>
使用方法
- 打开命令行,进入你的画廊文件夹,运行
npm install安装依赖 - 运行
node server.js启动服务器 - 在浏览器里打开
http://localhost:3000,就能看到实时更新的画廊了
代码说明
- 后端:用Node.js搭了个静态文件服务器,同时用
chokidar监听图片文件夹的变化,一旦有新增/删除/修改,就通过WebSocket把最新的图片列表推给前端。 - 前端:
- 接收后端推送的图片列表,对比当前列表自动新增或移除画廊元素
- 用CSS过渡动画实现了点击图片从原位置放大的全屏效果
- 定时给图片URL加时间戳,解决浏览器缓存导致修改后图片不刷新的问题
内容的提问来源于stack exchange,提问作者Vincent Zorzi
相关产品推荐
相关产品推荐

