hugo-teek is loading...

go壁纸api

最后更新于:

v1-2025.9.14-解决手机拍照的图片显示不全问题(成功解决)

提出问题

  1<!DOCTYPE html>
  2<html>
  3<head>
  4    <title>随机图片展示</title>
  5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6    <style>
  7        html, body {
  8            margin: 0;
  9            padding: 0;
 10            height: 100%;
 11            overflow: hidden;
 12        }
 13        img {
 14            object-fit: cover;
 15            width: 100%;
 16            height: 100%;
 17            background-color: #000;
 18        }
 19        .image-container {
 20            position: relative;
 21            width: 100%;
 22            height: 100%;
 23            background-color: #000;
 24        }
 25        .image-layer {
 26            position: absolute;
 27            top: 0;
 28            left: 0;
 29            width: 100%;
 30            height: 100%;
 31            opacity: 0;
 32            transform: scale(1.1);
 33        }
 34        
 35        .image-layer.transitioning {
 36            transition: opacity 2.5s cubic-bezier(0.25, 0.1, 0.25, 1), 
 37                       transform 2.5s cubic-bezier(0.25, 0.1, 0.25, 1);
 38        }
 39        
 40        .image-layer.active {
 41            opacity: 1;
 42            animation: breathe 8s ease-in-out infinite;
 43        }
 44        
 45        @keyframes breathe {
 46            0%, 100% {
 47                transform: scale(1);
 48            }
 49            50% {
 50                transform: scale(1.05);
 51            }
 52        }
 53    </style>
 54</head>
 55<body>
 56    <div class="image-container">
 57        <img class="image-layer" id="image1" src="" alt="">
 58        <img class="image-layer" id="image2" src="" alt="">
 59    </div>
 60
 61    <script>
 62        var images = {{ .ImagePaths }};
 63        var image1 = document.getElementById('image1');
 64        var image2 = document.getElementById('image2');
 65        var currentLayer = 1; // 当前显示的图层
 66        var imageInterval;
 67
 68        function preloadImage(src) {
 69            return new Promise((resolve, reject) => {
 70                const img = new Image();
 71                img.onload = () => resolve(src);
 72                img.onerror = () => reject(src);
 73                img.src = src;
 74            });
 75        }
 76
 77        let isTransitioning = false;
 78
 79        function fadeToNewImage(src) {
 80            if (isTransitioning) return;
 81            isTransitioning = true;
 82            
 83            const nextLayer = currentLayer === 1 ? 2 : 1;
 84            const currentImg = currentLayer === 1 ? image1 : image2;
 85            const nextImg = nextLayer === 1 ? image1 : image2;
 86
 87            preloadImage(src).then(loadedSrc => {
 88                // 在后台图层设置新图片
 89                nextImg.src = loadedSrc;
 90                nextImg.className = 'image-layer';
 91                
 92                // 获取当前图片的实时缩放值
 93                const currentTransform = window.getComputedStyle(currentImg).transform;
 94                let currentScale = 1;
 95                if (currentTransform && currentTransform !== 'none') {
 96                    const matrix = currentTransform.match(/matrix.*\((.+)\)/);
 97                    if (matrix) {
 98                        const values = matrix[1].split(', ');
 99                        currentScale = parseFloat(values[0]);
100                    }
101                }
102                
103                // 开始切换,保持当前缩放状态
104                currentImg.classList.add('transitioning');
105                nextImg.classList.add('transitioning');
106                
107                // 强制重绘
108                nextImg.offsetHeight;
109                
110                // 平滑切换
111                requestAnimationFrame(() => {
112                    // 当前图片从实时状态淡出
113                    if (currentImg.classList.contains('active')) {
114                        currentImg.classList.remove('active');
115                        currentImg.style.transform = `scale(${currentScale})`;
116                        currentImg.style.opacity = '1';
117                        
118                        requestAnimationFrame(() => {
119                            currentImg.style.opacity = '0';
120                            currentImg.style.transform = 'scale(0.95)';
121                        });
122                    }
123                    
124                    // 新图片淡入
125                    nextImg.style.opacity = '0';
126                    nextImg.style.transform = 'scale(1.1)';
127                    
128                    requestAnimationFrame(() => {
129                        nextImg.style.opacity = '1';
130                        nextImg.style.transform = 'scale(1)';
131                    });
132                });
133                
134                // 切换完成后启动呼吸动画
135                setTimeout(() => {
136                    // 清理旧图片
137                    currentImg.className = 'image-layer';
138                    currentImg.style.cssText = '';
139                    
140                    // 激活新图片并启动呼吸
141                    nextImg.className = 'image-layer active';
142                    nextImg.style.cssText = '';
143                    
144                    currentLayer = nextLayer;
145                    isTransitioning = false;
146                }, 2500);
147                
148            }).catch(() => {
149                isTransitioning = false;
150                setTimeout(changeImage, 500);
151            });
152        }
153
154        function changeImage() {
155            if (images.length === 0) return;
156            const randomSrc = images[Math.floor(Math.random() * images.length)];
157            fadeToNewImage(randomSrc);
158        }
159
160        // 初始化第一张图片
161        if (images.length > 0) {
162            const firstSrc = images[Math.floor(Math.random() * images.length)];
163            preloadImage(firstSrc).then(loadedSrc => {
164                image1.src = loadedSrc;
165                setTimeout(() => {
166                    image1.className = 'image-layer active';
167                }, 100);
168            }).catch(() => {
169                // 如果第一张图片加载失败,尝试下一张
170                setTimeout(changeImage, 500);
171            });
172        }
173
174        // 定时切换 (15秒)
175        imageInterval = setInterval(changeImage, 15000);
176
177        // 刷新图片列表
178        setInterval(function() {
179            fetch('/api/images')
180                .then(response => response.json())
181                .then(data => {
182                    images = data.images;
183                    if (images.length === 0) {
184                        clearInterval(imageInterval);
185                        image1.className = 'image-layer';
186                        image2.className = 'image-layer';
187                    } else {
188                        if (!imageInterval) {
189                            imageInterval = setInterval(changeImage, 15000);
190                        }
191                    }
192                })
193                .catch(error => console.error('Error fetching images:', error));
194        }, 60000);
195    </script>
196</body>
197</html>
198
199
200这段代码好像存在问题:
201
202之前虽然把照片的两边边框给处理掉了,但是像手机拍的照片,被轮播时,拍的人头直接看不到了,这个感觉🉐再优化下

豆包回答

问题核心在于当前使用的 object-fit: cover 会强制图片 “填满容器且保持比例”,导致手机拍摄的竖屏照片(通常为 3:49:16 比例)在横屏显示器(16:9 等宽屏比例)中被裁剪上下部分,从而丢失人像头部等关键内容。

优化思路是:优先保证人像等主体内容完整显示,同时兼顾画面填充效果,通过调整 object-fit 策略、增加背景适配、优化缩放逻辑实现平衡。以下是完整优化后的代码,关键修改已标注说明:

📌优化后完整代码

  1<!DOCTYPE html>
  2<html>
  3<head>
  4    <title>随机图片展示(人像优化版)</title>
  5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6    <style>
  7        html, body {
  8            margin: 0;
  9            padding: 0;
 10            height: 100%;
 11            overflow: hidden;
 12            /* 新增:深色背景过渡,避免图片切换时出现白边 */
 13            background: linear-gradient(135deg, #111 0%, #333 100%);
 14        }
 15        .image-container {
 16            position: relative;
 17            width: 100%;
 18            height: 100%;
 19        }
 20        .image-layer {
 21            position: absolute;
 22            top: 0;
 23            left: 0;
 24            width: 100%;
 25            height: 100%;
 26            opacity: 0;
 27            /* 关键修改1:将 scale(1.1) 改为 scale(1),减少初始裁剪 */
 28            transform: scale(1);
 29            /* 关键修改2:object-fit 从 cover 改为 contain,优先完整显示图片 */
 30            object-fit: contain;
 31            /* 关键修改3:设置背景色,图片未填满区域用深色过渡,避免突兀 */
 32            background-color: rgba(0, 0, 0, 0.8);
 33        }
 34        
 35        .image-layer.transitioning {
 36            /* 保留过渡动画,确保切换平滑 */
 37            transition: opacity 2.5s cubic-bezier(0.25, 0.1, 0.25, 1), 
 38                       transform 2.5s cubic-bezier(0.25, 0.1, 0.25, 1);
 39        }
 40        
 41        .image-layer.active {
 42            opacity: 1;
 43            /* 关键修改4:优化呼吸动画缩放比例,从 1.05 改为 1.03,减少边缘裁剪 */
 44            animation: breathe 10s ease-in-out infinite; /* 延长动画周期,更自然 */
 45        }
 46        
 47        @keyframes breathe {
 48            0%, 100% {
 49                transform: scale(1); /* 初始/结束状态:原尺寸 */
 50            }
 51            50% {
 52                transform: scale(1.03); /* 中间状态:轻微放大,避免过度裁剪 */
 53            }
 54        }
 55
 56        /* 新增:加载状态提示(可选,提升用户体验) */
 57        .loading {
 58            position: absolute;
 59            top: 50%;
 60            left: 50%;
 61            transform: translate(-50%, -50%);
 62            color: #fff;
 63            font-size: 18px;
 64            z-index: 10;
 65        }
 66    </style>
 67</head>
 68<body>
 69    <div class="image-container">
 70        <!-- 新增:加载提示 -->
 71        <div class="loading" id="loading">图片加载中...</div>
 72        <!-- 图层保持不变 -->
 73        <img class="image-layer" id="image1" src="" alt="轮播图片">
 74        <img class="image-layer" id="image2" src="" alt="轮播图片">
 75    </div>
 76
 77    <script>
 78        var images = {{ .ImagePaths }}; // 保持原有模板变量
 79        var image1 = document.getElementById('image1');
 80        var image2 = document.getElementById('image2');
 81        var loading = document.getElementById('loading');
 82        var currentLayer = 1;
 83        var imageInterval;
 84        var isTransitioning = false;
 85
 86        // 1. 保留预加载逻辑,确保图片完全加载后再显示
 87        function preloadImage(src) {
 88            return new Promise((resolve, reject) => {
 89                const img = new Image();
 90                img.onload = () => resolve(src);
 91                img.onerror = () => reject(new Error(`图片加载失败: ${src}`));
 92                img.src = src;
 93            });
 94        }
 95
 96        // 2. 关键优化:根据图片宽高比动态调整显示策略(进一步减少裁剪)
 97        function adjustImageDisplay(imgElement, src) {
 98            return new Promise((resolve) => {
 99                const tempImg = new Image();
100                tempImg.onload = () => {
101                    const imgRatio = tempImg.width / tempImg.height; // 图片宽高比
102                    const containerRatio = window.innerWidth / window.innerHeight; // 容器宽高比
103
104                    // 逻辑:如果是竖屏图片(手机拍摄,宽高比 < 1),强制用 contain 保证完整;
105                    // 如果是横屏图片,可根据容器比例微调(可选 cover,根据需求切换)
106                    if (imgRatio < 1) { // 竖屏图片(如手机人像照)
107                        imgElement.style.objectFit = 'contain';
108                    } else { // 横屏图片
109                        imgElement.style.objectFit = 'contain'; // 也可改为 cover,根据需求选择
110                    }
111                    resolve();
112                };
113                tempImg.src = src;
114            });
115        }
116
117        // 3. 优化切换逻辑:确保加载+适配完成后再开始过渡
118        async function fadeToNewImage(src) {
119            if (isTransitioning || !src) return;
120            isTransitioning = true;
121
122            const nextLayer = currentLayer === 1 ? 2 : 1;
123            const currentImg = currentLayer === 1 ? image1 : image2;
124            const nextImg = nextLayer === 1 ? image1 : image2;
125
126            try {
127                // 步骤1:预加载图片 + 动态适配显示策略
128                await preloadImage(src);
129                await adjustImageDisplay(nextImg, src);
130
131                // 步骤2:设置新图片到后台图层
132                nextImg.src = src;
133                nextImg.className = 'image-layer';
134
135                // 步骤3:获取当前图层的实时状态(保持过渡连贯性)
136                const currentTransform = window.getComputedStyle(currentImg).transform;
137                let currentScale = 1;
138                if (currentTransform && currentTransform !== 'none') {
139                    const matrix = currentTransform.match(/matrix.*\((.+)\)/);
140                    if (matrix) {
141                        const values = matrix[1].split(', ');
142                        currentScale = parseFloat(values[0]) || 1;
143                    }
144                }
145
146                // 步骤4:开始平滑过渡
147                currentImg.classList.add('transitioning');
148                nextImg.classList.add('transitioning');
149                nextImg.offsetHeight; // 强制重绘,确保过渡生效
150
151                // 步骤5:当前图层淡出,新图层淡入
152                requestAnimationFrame(() => {
153                    // 当前图层:从当前缩放状态平滑淡出
154                    if (currentImg.classList.contains('active')) {
155                        currentImg.style.transform = `scale(${currentScale})`;
156                        currentImg.style.opacity = '1';
157                        requestAnimationFrame(() => {
158                            currentImg.style.opacity = '0';
159                            currentImg.style.transform = 'scale(0.98)'; // 轻微缩小,避免突兀
160                        });
161                    }
162
163                    // 新图层:从轻微放大状态淡入(匹配呼吸动画初始值)
164                    nextImg.style.opacity = '0';
165                    nextImg.style.transform = 'scale(1)';
166                    requestAnimationFrame(() => {
167                        nextImg.style.opacity = '1';
168                        nextImg.style.transform = 'scale(1)';
169                    });
170                });
171
172                // 步骤6:过渡完成,激活新图层的呼吸动画
173                setTimeout(() => {
174                    currentImg.className = 'image-layer';
175                    currentImg.style.cssText = ''; // 清除旧样式,避免干扰
176                    nextImg.className = 'image-layer active';
177                    nextImg.style.cssText = '';
178                    currentLayer = nextLayer;
179                    isTransitioning = false;
180                }, 2500);
181
182            } catch (error) {
183                console.error(error);
184                isTransitioning = false;
185                setTimeout(changeImage, 1000); // 失败后延迟重试
186            }
187        }
188
189        // 4. 初始化第一张图片(新增加载提示隐藏逻辑)
190        async function initFirstImage() {
191            if (images.length === 0) {
192                loading.textContent = '暂无图片可展示';
193                return;
194            }
195            const firstSrc = images[Math.floor(Math.random() * images.length)];
196            try {
197                await preloadImage(firstSrc);
198                await adjustImageDisplay(image1, firstSrc);
199                image1.src = firstSrc;
200                // 延迟显示,确保动画平滑
201                setTimeout(() => {
202                    image1.className = 'image-layer active';
203                    loading.style.opacity = '0'; // 隐藏加载提示
204                    setTimeout(() => loading.style.display = 'none', 500);
205                }, 300);
206            } catch (error) {
207                console.error('初始化图片失败:', error);
208                loading.textContent = '图片加载失败,正在重试...';
209                setTimeout(initFirstImage, 1500); // 重试
210            }
211        }
212
213        // 5. 随机切换图片(逻辑不变)
214        function changeImage() {
215            if (images.length === 0) {
216                clearInterval(imageInterval);
217                return;
218            }
219            const randomSrc = images[Math.floor(Math.random() * images.length)];
220            fadeToNewImage(randomSrc);
221        }
222
223        // 6. 初始化执行
224        initFirstImage();
225
226        // 7. 定时切换(保持15秒,可根据需求调整)
227        imageInterval = setInterval(changeImage, 15000);
228
229        // 8. 刷新图片列表(逻辑不变,新增错误处理)
230        setInterval(async () => {
231            try {
232                const response = await fetch('/api/images');
233                if (!response.ok) throw new Error('获取图片列表失败');
234                const data = await response.json();
235                images = data.images || [];
236
237                if (images.length === 0) {
238                    clearInterval(imageInterval);
239                    image1.className = 'image-layer';
240                    image2.className = 'image-layer';
241                    loading.style.display = 'block';
242                    loading.textContent = '暂无图片可展示';
243                } else {
244                    if (!imageInterval) {
245                        imageInterval = setInterval(changeImage, 15000);
246                        loading.style.display = 'none';
247                    }
248                }
249            } catch (error) {
250                console.error('刷新图片列表失败:', error);
251            }
252        }, 60000);
253    </script>
254</body>
255</html>

📌核心优化点说明

优化方向原问题解决方案
图片裁剪问题object-fit: cover 裁剪竖屏照片改为 object-fit: contain,优先保证图片完整显示,未填满区域用深色背景过渡
呼吸动画过度缩放scale(1.05) 放大导致边缘裁剪调整为 scale(1.03),延长动画周期至 10 秒,减少裁剪风险
初始状态裁剪初始 scale(1.1) 直接裁剪图片改为 scale(1),从原尺寸开始动画,避免初始丢失内容
动态适配策略未区分横竖屏图片新增宽高比判断:竖屏图片强制 contain,横屏可灵活切换(根据需求调整)
用户体验加载时无提示,失败无反馈增加加载中提示,失败自动重试,优化错误文案

📌额外建议(根据实际场景选择)

  1. 如果希望横屏图片填满容器: 在 adjustImageDisplay 函数中,将横屏图片(imgRatio > 1)的 objectFit 改回 cover,竖屏图片保持 contain,实现 “横屏填充满,竖屏保完整”。
  2. 如果图片尺寸差异过大: 可在后端接口 /api/images 中返回图片宽高比信息,前端直接使用,减少前端临时计算的性能消耗。
  3. 增加图片居中裁剪(折中方案): 若 contain 导致背景过多,可改用 object-fit: scale-down(优先完整显示,超出时裁剪),或通过 object-position: center 确保裁剪时保留中间区域(人像通常在中间)。

通过以上优化,手机拍摄的竖屏人像照会优先完整显示,同时兼顾整体视觉效果,避免头部等关键内容被裁剪。

效果测试

1[root@wiki templates]# pwd
2/root/img-server-fxj/templates
3[root@wiki templates]# ls
4index.qx  index.qx.bak  index.qx-v1  no-images.qx
5[root@wiki templates]# 
6
7
8#index.qx-v1 这一般OK的。

存在问题

人像照片可以正常显示了,但是两边出现了黑框。

image-20250914081151760

v2-2025.9.14-解决 让 照片 两边的边框为高斯模糊/毛玻璃效果(不理想)

提出问题

1在以上代码基础上,能否把轮播图片时  2边的黑框 改成高斯模糊 毛玻璃 风格呢,这个比较好看些

要将轮播图片两侧的黑框改为为高斯模糊(毛玻璃)风格,我们可以利用 CSS 的backdrop-filter属性结合伪元素来实现。这种效果能让图片边缘与背景自然融合,同时保持图片主体清晰。以下是修改后的代码:

带毛玻璃效果的图片轮播

V1

创建时间:07:49

  1<!DOCTYPE html>
  2<html>
  3<head>
  4    <title>随机图片展示(毛玻璃边框版)</title>
  5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6    <style>
  7        html, body {
  8            margin: 0;
  9            padding: 0;
 10            height: 100%;
 11            overflow: hidden;
 12            /* 背景图用于增强毛玻璃效果的层次感 */
 13            background-image: url('https://picsum.photos/id/1015/1920/1080');
 14            background-size: cover;
 15            background-position: center;
 16            background-attachment: fixed;
 17        }
 18        .image-container {
 19            position: relative;
 20            width: 100%;
 21            height: 100%;
 22        }
 23        
 24        /* 新增:左右毛玻璃边框 */
 25        .image-container::before,
 26        .image-container::after {
 27            content: '';
 28            position: absolute;
 29            top: 0;
 30            height: 100%;
 31            width: 15%; /* 边框宽度,可根据需要调整 */
 32            z-index: 5; /* 确保在图片上方 */
 33            pointer-events: none; /* 不影响图片交互 */
 34        }
 35        
 36        .image-container::before {
 37            left: 0;
 38            /* 左侧渐变模糊效果 */
 39            background: linear-gradient(90deg, 
 40                rgba(255, 255, 255, 0.15) 0%, 
 41                rgba(255, 255, 255, 0) 100%);
 42            backdrop-filter: blur(10px);
 43            -webkit-backdrop-filter: blur(10px);
 44        }
 45        
 46        .image-container::after {
 47            right: 0;
 48            /* 右侧渐变模糊效果 */
 49            background: linear-gradient(270deg, 
 50                rgba(255, 255, 255, 0.15) 0%, 
 51                rgba(255, 255, 255, 0) 100%);
 52            backdrop-filter: blur(10px);
 53            -webkit-backdrop-filter: blur(10px);
 54        }
 55
 56        .image-layer {
 57            position: absolute;
 58            top: 0;
 59            left: 0;
 60            width: 100%;
 61            height: 100%;
 62            opacity: 0;
 63            transform: scale(1);
 64            object-fit: contain;
 65            /* 轻微透明让背景渗透,增强融合感 */
 66            opacity: 0.98;
 67        }
 68        
 69        .image-layer.transitioning {
 70            transition: opacity 2.5s cubic-bezier(0.25, 0.1, 0.25, 1), 
 71                       transform 2.5s cubic-bezier(0.25, 0.1, 0.25, 1);
 72        }
 73        
 74        .image-layer.active {
 75            opacity: 1;
 76            animation: breathe 10s ease-in-out infinite;
 77        }
 78        
 79        @keyframes breathe {
 80            0%, 100% {
 81                transform: scale(1);
 82            }
 83            50% {
 84                transform: scale(1.03);
 85            }
 86        }
 87
 88        .loading {
 89            position: absolute;
 90            top: 50%;
 91            left: 50%;
 92            transform: translate(-50%, -50%);
 93            color: #fff;
 94            font-size: 18px;
 95            z-index: 10;
 96            text-shadow: 0 2px 4px rgba(0,0,0,0.3);
 97            backdrop-filter: blur(5px);
 98            -webkit-backdrop-filter: blur(5px);
 99            padding: 10px 20px;
100            border-radius: 8px;
101            background-color: rgba(0,0,0,0.2);
102        }
103    </style>
104</head>
105<body>
106    <div class="image-container">
107        <div class="loading" id="loading">图片加载中...</div>
108        <img class="image-layer" id="image1" src="" alt="轮播图片">
109        <img class="image-layer" id="image2" src="" alt="轮播图片">
110    </div>
111
112    <script>
113        // 示例图片地址,实际使用时替换为{{ .ImagePaths }}
114        var images = [
115            'https://picsum.photos/id/64/800/1200', // 竖屏示例
116            'https://picsum.photos/id/65/1200/800', // 横屏示例
117            'https://picsum.photos/id/91/800/1200', // 竖屏示例
118            'https://picsum.photos/id/96/1200/800'  // 横屏示例
119        ];
120        
121        var image1 = document.getElementById('image1');
122        var image2 = document.getElementById('image2');
123        var loading = document.getElementById('loading');
124        var currentLayer = 1;
125        var imageInterval;
126        var isTransitioning = false;
127
128        function preloadImage(src) {
129            return new Promise((resolve, reject) => {
130                const img = new Image();
131                img.onload = () => resolve(src);
132                img.onerror = () => reject(new Error(`图片加载失败: ${src}`));
133                img.src = src;
134            });
135        }
136
137        function adjustImageDisplay(imgElement, src) {
138            return new Promise((resolve) => {
139                const tempImg = new Image();
140                tempImg.onload = () => {
141                    const imgRatio = tempImg.width / tempImg.height;
142                    const containerRatio = window.innerWidth / window.innerHeight;
143
144                    if (imgRatio < 1) {
145                        imgElement.style.objectFit = 'contain';
146                    } else {
147                        imgElement.style.objectFit = 'contain';
148                    }
149                    resolve();
150                };
151                tempImg.src = src;
152            });
153        }
154
155        async function fadeToNewImage(src) {
156            if (isTransitioning || !src) return;
157            isTransitioning = true;
158
159            const nextLayer = currentLayer === 1 ? 2 : 1;
160            const currentImg = currentLayer === 1 ? image1 : image2;
161            const nextImg = nextLayer === 1 ? image1 : image2;
162
163            try {
164                await preloadImage(src);
165                await adjustImageDisplay(nextImg, src);
166
167                nextImg.src = src;
168                nextImg.className = 'image-layer';
169
170                const currentTransform = window.getComputedStyle(currentImg).transform;
171                let currentScale = 1;
172                if (currentTransform && currentTransform !== 'none') {
173                    const matrix = currentTransform.match(/matrix.*\((.+)\)/);
174                    if (matrix) {
175                        const values = matrix[1].split(', ');
176                        currentScale = parseFloat(values[0]) || 1;
177                    }
178                }
179
180                currentImg.classList.add('transitioning');
181                nextImg.classList.add('transitioning');
182                nextImg.offsetHeight;
183
184                requestAnimationFrame(() => {
185                    if (currentImg.classList.contains('active')) {
186                        currentImg.style.transform = `scale(${currentScale})`;
187                        currentImg.style.opacity = '1';
188                        requestAnimationFrame(() => {
189                            currentImg.style.opacity = '0';
190                            currentImg.style.transform = 'scale(0.98)';
191                        });
192                    }
193
194                    nextImg.style.opacity = '0';
195                    nextImg.style.transform = 'scale(1)';
196                    requestAnimationFrame(() => {
197                        nextImg.style.opacity = '1';
198                        nextImg.style.transform = 'scale(1)';
199                    });
200                });
201
202                setTimeout(() => {
203                    currentImg.className = 'image-layer';
204                    currentImg.style.cssText = '';
205                    nextImg.className = 'image-layer active';
206                    nextImg.style.cssText = '';
207                    currentLayer = nextLayer;
208                    isTransitioning = false;
209                }, 2500);
210
211            } catch (error) {
212                console.error(error);
213                isTransitioning = false;
214                setTimeout(changeImage, 1000);
215            }
216        }
217
218        async function initFirstImage() {
219            if (images.length === 0) {
220                loading.textContent = '暂无图片可展示';
221                return;
222            }
223            const firstSrc = images[Math.floor(Math.random() * images.length)];
224            try {
225                await preloadImage(firstSrc);
226                await adjustImageDisplay(image1, firstSrc);
227                image1.src = firstSrc;
228                setTimeout(() => {
229                    image1.className = 'image-layer active';
230                    loading.style.opacity = '0';
231                    setTimeout(() => loading.style.display = 'none', 500);
232                }, 300);
233            } catch (error) {
234                console.error('初始化图片失败:', error);
235                loading.textContent = '图片加载失败,正在重试...';
236                setTimeout(initFirstImage, 1500);
237            }
238        }
239
240        function changeImage() {
241            if (images.length === 0) {
242                clearInterval(imageInterval);
243                return;
244            }
245            const randomSrc = images[Math.floor(Math.random() * images.length)];
246            fadeToNewImage(randomSrc);
247        }
248
249        initFirstImage();
250        imageInterval = setInterval(changeImage, 15000);
251
252        setInterval(async () => {
253            try {
254                const response = await fetch('/api/images');
255                if (!response.ok) throw new Error('获取图片列表失败');
256                const data = await response.json();
257                images = data.images || [];
258
259                if (images.length === 0) {
260                    clearInterval(imageInterval);
261                    image1.className = 'image-layer';
262                    image2.className = 'image-layer';
263                    loading.style.display = 'block';
264                    loading.textContent = '暂无图片可展示';
265                } else {
266                    if (!imageInterval) {
267                        imageInterval = setInterval(changeImage, 15000);
268                        loading.style.display = 'none';
269                    }
270                }
271            } catch (error) {
272                console.error('刷新图片列表失败:', error);
273            }
274        }, 60000);
275    </script>
276</body>
277</html>

📌主要修改说明

  1. 毛玻璃边框实现
    • 使用.image-container::before::after伪元素创建左右边框
    • 通过backdrop-filter: blur(10px)实现高斯模糊效果
    • 配合渐变背景linear-gradient实现从模糊到透明的过渡,使边框更自然
  2. 背景增强
    • 添加了一张固定背景图,增强毛玻璃效果的层次感
    • 毛玻璃效果会模糊其下方的背景内容,创造深度感
  3. 细节优化
    • 图片设置轻微透明(opacity: 0.98),让背景能轻微渗透,增强融合感
    • 加载提示也添加了轻微的毛玻璃效果,保持风格统一
    • 调整了毛玻璃的透明度和模糊程度,确保效果美观且不影响图片主体观看
  4. 兼容性考虑
    • 添加了-webkit-backdrop-filter前缀以支持 WebKit 内核浏览器
    • 毛玻璃效果在不支持的浏览器中会自动降级为半透明效果

你可以通过调整这些值来优化效果:

  • 边框宽度:修改.image-container::before::afterwidth属性
  • 模糊程度:调整backdrop-filter: blur(10px)中的像素值
  • 边框透明度:修改渐变中的rgba(255, 255, 255, 0.15)的 alpha 值

这种毛玻璃效果能很好地解决图片两侧空白区域的视觉问题,同时增添现代感和高级感。

效果测试(存在问题)

image-20250914081448268

v3-2025.9.14-为啥自己本地图片不见了

问题描述

1我本来图片 路径 在images目录下,但你修改的这版后哦,为啥我本地的图片没法展示了?

豆包输出

问题出在示例代码中使用了在线图片地址(如https://picsum.photos/...),而没有使用你本地images目录下的图片路径。要解决这个问题,需要将代码中的图片路径修改为你本地图片的正确路径。

以下是修改后的代码,适配适配本地images目录下的图片:

适配本地图片的毛玻璃边框轮播

V1

创建时间:07:57

  1<!DOCTYPE html>
  2<html>
  3<head>
  4    <title>随机图片展示(本地图片版)</title>
  5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6    <style>
  7        html, body {
  8            margin: 0;
  9            padding: 0;
 10            height: 100%;
 11            overflow: hidden;
 12            /* 使用本地背景图或纯色背景 */
 13            background-color: #222; /* 改为深色背景,避免与本地图片冲突 */
 14        }
 15        .image-container {
 16            position: relative;
 17            width: 100%;
 18            height: 100%;
 19        }
 20        
 21        /* 左右毛玻璃边框 */
 22        .image-container::before,
 23        .image-container::after {
 24            content: '';
 25            position: absolute;
 26            top: 0;
 27            height: 100%;
 28            width: 15%;
 29            z-index: 5;
 30            pointer-events: none;
 31        }
 32        
 33        .image-container::before {
 34            left: 0;
 35            background: linear-gradient(90deg, 
 36                rgba(0, 0, 0, 0.3) 0%, 
 37                rgba(0, 0, 0, 0) 100%);
 38            backdrop-filter: blur(10px);
 39            -webkit-backdrop-filter: blur(10px);
 40        }
 41        
 42        .image-container::after {
 43            right: 0;
 44            background: linear-gradient(270deg, 
 45                rgba(0, 0, 0, 0.3) 0%, 
 46                rgba(0, 0, 0, 0) 100%);
 47            backdrop-filter: blur(10px);
 48            -webkit-backdrop-filter: blur(10px);
 49        }
 50
 51        .image-layer {
 52            position: absolute;
 53            top: 0;
 54            left: 0;
 55            width: 100%;
 56            height: 100%;
 57            opacity: 0;
 58            transform: scale(1);
 59            object-fit: contain;
 60            opacity: 0.98;
 61        }
 62        
 63        .image-layer.transitioning {
 64            transition: opacity 2.5s cubic-bezier(0.25, 0.1, 0.25, 1), 
 65                       transform 2.5s cubic-bezier(0.25, 0.1, 0.25, 1);
 66        }
 67        
 68        .image-layer.active {
 69            opacity: 1;
 70            animation: breathe 10s ease-in-out infinite;
 71        }
 72        
 73        @keyframes breathe {
 74            0%, 100% {
 75                transform: scale(1);
 76            }
 77            50% {
 78                transform: scale(1.03);
 79            }
 80        }
 81
 82        .loading {
 83            position: absolute;
 84            top: 50%;
 85            left: 50%;
 86            transform: translate(-50%, -50%);
 87            color: #fff;
 88            font-size: 18px;
 89            z-index: 10;
 90            text-shadow: 0 2px 4px rgba(0,0,0,0.3);
 91            backdrop-filter: blur(5px);
 92            -webkit-backdrop-filter: blur(5px);
 93            padding: 10px 20px;
 94            border-radius: 8px;
 95            background-color: rgba(0,0,0,0.2);
 96        }
 97    </style>
 98</head>
 99<body>
100    <div class="image-container">
101        <div class="loading" id="loading">图片加载中...</div>
102        <img class="image-layer" id="image1" src="" alt="轮播图片">
103        <img class="image-layer" id="image2" src="" alt="轮播图片">
104    </div>
105
106    <script>
107        // 关键修改:使用本地images目录下的图片
108        // 请将以下列表替换为你实际的图片文件名
109        var images = [
110            'images/photo1.jpg',   // 替换为你的图片1
111            'images/photo2.png',   // 替换为你的图片2
112            'images/photo3.jpg',   // 替换为你的图片3
113            'images/photo4.png'    // 替换为你的图片4
114        ];
115        
116        var image1 = document.getElementById('image1');
117        var image2 = document.getElementById('image2');
118        var loading = document.getElementById('loading');
119        var currentLayer = 1;
120        var imageInterval;
121        var isTransitioning = false;
122
123        // 新增:检查图片是否存在的辅助函数
124        function checkImageExists(src) {
125            return new Promise((resolve) => {
126                const img = new Image();
127                img.onload = () => resolve(true);
128                img.onerror = () => resolve(false);
129                img.src = src;
130            });
131        }
132
133        function preloadImage(src) {
134            return new Promise((resolve, reject) => {
135                const img = new Image();
136                img.onload = () => resolve(src);
137                img.onerror = () => reject(new Error(`图片加载失败: ${src}(请检查路径是否正确)`));
138                img.src = src;
139            });
140        }
141
142        function adjustImageDisplay(imgElement, src) {
143            return new Promise((resolve) => {
144                const tempImg = new Image();
145                tempImg.onload = () => {
146                    const imgRatio = tempImg.width / tempImg.height;
147                    const containerRatio = window.innerWidth / window.innerHeight;
148
149                    if (imgRatio < 1) {
150                        imgElement.style.objectFit = 'contain';
151                    } else {
152                        imgElement.style.objectFit = 'contain';
153                    }
154                    resolve();
155                };
156                tempImg.src = src;
157            });
158        }
159
160        async function fadeToNewImage(src) {
161            if (isTransitioning || !src) return;
162            isTransitioning = true;
163
164            const nextLayer = currentLayer === 1 ? 2 : 1;
165            const currentImg = currentLayer === 1 ? image1 : image2;
166            const nextImg = nextLayer === 1 ? image1 : image2;
167
168            try {
169                // 先检查图片是否存在
170                const exists = await checkImageExists(src);
171                if (!exists) {
172                    throw new Error(`图片不存在: ${src}`);
173                }
174
175                await preloadImage(src);
176                await adjustImageDisplay(nextImg, src);
177
178                nextImg.src = src;
179                nextImg.className = 'image-layer';
180
181                const currentTransform = window.getComputedStyle(currentImg).transform;
182                let currentScale = 1;
183                if (currentTransform && currentTransform !== 'none') {
184                    const matrix = currentTransform.match(/matrix.*\((.+)\)/);
185                    if (matrix) {
186                        const values = matrix[1].split(', ');
187                        currentScale = parseFloat(values[0]) || 1;
188                    }
189                }
190
191                currentImg.classList.add('transitioning');
192                nextImg.classList.add('transitioning');
193                nextImg.offsetHeight;
194
195                requestAnimationFrame(() => {
196                    if (currentImg.classList.contains('active')) {
197                        currentImg.style.transform = `scale(${currentScale})`;
198                        currentImg.style.opacity = '1';
199                        requestAnimationFrame(() => {
200                            currentImg.style.opacity = '0';
201                            currentImg.style.transform = 'scale(0.98)';
202                        });
203                    }
204
205                    nextImg.style.opacity = '0';
206                    nextImg.style.transform = 'scale(1)';
207                    requestAnimationFrame(() => {
208                        nextImg.style.opacity = '1';
209                        nextImg.style.transform = 'scale(1)';
210                    });
211                });
212
213                setTimeout(() => {
214                    currentImg.className = 'image-layer';
215                    currentImg.style.cssText = '';
216                    nextImg.className = 'image-layer active';
217                    nextImg.style.cssText = '';
218                    currentLayer = nextLayer;
219                    isTransitioning = false;
220                }, 2500);
221
222            } catch (error) {
223                console.error(error);
224                loading.textContent = error.message;
225                isTransitioning = false;
226                setTimeout(changeImage, 2000);
227            }
228        }
229
230        async function initFirstImage() {
231            if (images.length === 0) {
232                loading.textContent = '暂无图片可展示';
233                return;
234            }
235            const firstSrc = images[Math.floor(Math.random() * images.length)];
236            try {
237                await preloadImage(firstSrc);
238                await adjustImageDisplay(image1, firstSrc);
239                image1.src = firstSrc;
240                setTimeout(() => {
241                    image1.className = 'image-layer active';
242                    loading.style.opacity = '0';
243                    setTimeout(() => loading.style.display = 'none', 500);
244                }, 300);
245            } catch (error) {
246                console.error('初始化图片失败:', error);
247                loading.textContent = error.message;
248                setTimeout(initFirstImage, 2000);
249            }
250        }
251
252        function changeImage() {
253            if (images.length === 0) {
254                clearInterval(imageInterval);
255                return;
256            }
257            const randomSrc = images[Math.floor(Math.random() * images.length)];
258            fadeToNewImage(randomSrc);
259        }
260
261        // 初始化本地图片展示
262        initFirstImage();
263        imageInterval = setInterval(changeImage, 15000);
264
265        // 注释掉远程获取图片的代码,因为我们使用本地图片
266        /*
267        setInterval(async () => {
268            try {
269                const response = await fetch('/api/images');
270                if (!response.ok) throw new Error('获取图片列表失败');
271                const data = await response.json();
272                images = data.images || [];
273
274                if (images.length === 0) {
275                    clearInterval(imageInterval);
276                    image1.className = 'image-layer';
277                    image2.className = 'image-layer';
278                    loading.style.display = 'block';
279                    loading.textContent = '暂无图片可展示';
280                } else {
281                    if (!imageInterval) {
282                        imageInterval = setInterval(changeImage, 15000);
283                        loading.style.display = 'none';
284                    }
285                }
286            } catch (error) {
287                console.error('刷新图片列表失败:', error);
288            }
289        }, 60000);
290        */
291    </script>
292</body>
293</html>

📌关键修改说明

  1. 图片路径调整
    • images数组中的图片路径修改为本地路径格式:'images/文件名'
    • 请务必将示例中的photo1.jpg等替换为你实际的图片文件名
  2. 本地适配优化
    • 注释掉了从远程 API 获取图片列表的代码,因为我们使用本地图片
    • 背景从在线图片改为深色纯色背景,避免与本地图片风格冲突
  3. 错误处理增强
    • 新增了checkImageExists函数,专门检查本地图片是否存在
    • 错误提示中会显示具体的图片路径,方便你排查路径问题
  4. 毛玻璃效果调整
    • 边框颜色从白色系改为深色系(rgba(0, 0, 0, 0.3)),更适合本地图片展示

📌排查本地图片不显示的常见问题

  1. 路径是否正确
    • 确保你的 HTML 文件和images目录在同一级目录
    • 例如:index.htmlimages文件夹平级,图片放在images
  2. 文件名是否正确
    • 注意文件名的大小写(尤其是在 Linux/macOS 系统)
    • 扩展名是否正确(是jpg还是jpegpng还是gif
  3. 文件权限问题
    • 确保图片文件有可读权限

如果仍然无法显示,可以打开浏览器的开发者工具(F12),查看控制台中的错误信息,那里会显示具体的图片加载失败原因。

v4-2025.9.14-不能自动扫描目录,需结合后端(待解决)

问题描述

1var images = [
2            'images/photo1.jpg',   // 替换为你的图片1
3            'images/photo2.png',   // 替换为你的图片2
4            'images/photo3.jpg',   // 替换为你的图片3
5            'images/photo4.png'    // 替换为你的图片4
6        ];
7        
8
9这里我不想每次都手动写路径,能不能自动扫描这个images目录下的图片呢?

豆包输出

要实现自动扫描images目录下的图片并动态加载,需要结合后端程序来实现目录扫描(因为浏览器的安全限制,JavaScript 无法直接访问本地文件系统)。以下是一个前后端结合的解决方案:

📌实现思路

  1. 后端(Go)提供一个 API 接口,用于扫描images目录并返回所有图片路径
  2. 前端通过这个 API 获取图片列表,而不是手动维护路径数组

📌前端代码修改(HTML/JavaScript)

自动扫描图片目录的轮播

V1

创建时间:07:59

  1<!DOCTYPE html>
  2<html>
  3<head>
  4    <title>随机图片展示(自动扫描版)</title>
  5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6    <style>
  7        /* 保持原有样式不变 */
  8        html, body {
  9            margin: 0;
 10            padding: 0;
 11            height: 100%;
 12            overflow: hidden;
 13            background-color: #222;
 14        }
 15        .image-container {
 16            position: relative;
 17            width: 100%;
 18            height: 100%;
 19        }
 20        
 21        .image-container::before,
 22        .image-container::after {
 23            content: '';
 24            position: absolute;
 25            top: 0;
 26            height: 100%;
 27            width: 15%;
 28            z-index: 5;
 29            pointer-events: none;
 30        }
 31        
 32        .image-container::before {
 33            left: 0;
 34            background: linear-gradient(90deg, 
 35                rgba(0, 0, 0, 0.3) 0%, 
 36                rgba(0, 0, 0, 0) 100%);
 37            backdrop-filter: blur(10px);
 38            -webkit-backdrop-filter: blur(10px);
 39        }
 40        
 41        .image-container::after {
 42            right: 0;
 43            background: linear-gradient(270deg, 
 44                rgba(0, 0, 0, 0.3) 0%, 
 45                rgba(0, 0, 0, 0) 100%);
 46            backdrop-filter: blur(10px);
 47            -webkit-backdrop-filter: blur(10px);
 48        }
 49
 50        .image-layer {
 51            position: absolute;
 52            top: 0;
 53            left: 0;
 54            width: 100%;
 55            height: 100%;
 56            opacity: 0;
 57            transform: scale(1);
 58            object-fit: contain;
 59            opacity: 0.98;
 60        }
 61        
 62        .image-layer.transitioning {
 63            transition: opacity 2.5s cubic-bezier(0.25, 0.1, 0.25, 1), 
 64                       transform 2.5s cubic-bezier(0.25, 0.1, 0.25, 1);
 65        }
 66        
 67        .image-layer.active {
 68            opacity: 1;
 69            animation: breathe 10s ease-in-out infinite;
 70        }
 71        
 72        @keyframes breathe {
 73            0%, 100% {
 74                transform: scale(1);
 75            }
 76            50% {
 77                transform: scale(1.03);
 78            }
 79        }
 80
 81        .loading {
 82            position: absolute;
 83            top: 50%;
 84            left: 50%;
 85            transform: translate(-50%, -50%);
 86            color: #fff;
 87            font-size: 18px;
 88            z-index: 10;
 89            text-shadow: 0 2px 4px rgba(0,0,0,0.3);
 90            backdrop-filter: blur(5px);
 91            -webkit-backdrop-filter: blur(5px);
 92            padding: 10px 20px;
 93            border-radius: 8px;
 94            background-color: rgba(0,0,0,0.2);
 95        }
 96    </style>
 97</head>
 98<body>
 99    <div class="image-container">
100        <div class="loading" id="loading">加载图片列表中...</div>
101        <img class="image-layer" id="image1" src="" alt="轮播图片">
102        <img class="image-layer" id="image2" src="" alt="轮播图片">
103    </div>
104
105    <script>
106        var images = [];  // 空数组,将从API获取
107        var image1 = document.getElementById('image1');
108        var image2 = document.getElementById('image2');
109        var loading = document.getElementById('loading');
110        var currentLayer = 1;
111        var imageInterval;
112        var isTransitioning = false;
113
114        // 从API获取图片列表
115        async function fetchImageList() {
116            try {
117                const response = await fetch('/api/images');
118                if (!response.ok) {
119                    throw new Error(`获取图片列表失败: ${response.status}`);
120                }
121                const data = await response.json();
122                return data.images || [];
123            } catch (error) {
124                console.error('获取图片列表出错:', error);
125                return [];
126            }
127        }
128
129        function preloadImage(src) {
130            return new Promise((resolve, reject) => {
131                const img = new Image();
132                img.onload = () => resolve(src);
133                img.onerror = () => reject(new Error(`图片加载失败: ${src}`));
134                img.src = src;
135            });
136        }
137
138        function adjustImageDisplay(imgElement, src) {
139            return new Promise((resolve) => {
140                const tempImg = new Image();
141                tempImg.onload = () => {
142                    const imgRatio = tempImg.width / tempImg.height;
143                    const containerRatio = window.innerWidth / window.innerHeight;
144
145                    if (imgRatio < 1) {
146                        imgElement.style.objectFit = 'contain';
147                    } else {
148                        imgElement.style.objectFit = 'contain';
149                    }
150                    resolve();
151                };
152                tempImg.src = src;
153            });
154        }
155
156        async function fadeToNewImage(src) {
157            if (isTransitioning || !src) return;
158            isTransitioning = true;
159
160            const nextLayer = currentLayer === 1 ? 2 : 1;
161            const currentImg = currentLayer === 1 ? image1 : image2;
162            const nextImg = nextLayer === 1 ? image1 : image2;
163
164            try {
165                await preloadImage(src);
166                await adjustImageDisplay(nextImg, src);
167
168                nextImg.src = src;
169                nextImg.className = 'image-layer';
170
171                const currentTransform = window.getComputedStyle(currentImg).transform;
172                let currentScale = 1;
173                if (currentTransform && currentTransform !== 'none') {
174                    const matrix = currentTransform.match(/matrix.*\((.+)\)/);
175                    if (matrix) {
176                        const values = matrix[1].split(', ');
177                        currentScale = parseFloat(values[0]) || 1;
178                    }
179                }
180
181                currentImg.classList.add('transitioning');
182                nextImg.classList.add('transitioning');
183                nextImg.offsetHeight;
184
185                requestAnimationFrame(() => {
186                    if (currentImg.classList.contains('active')) {
187                        currentImg.style.transform = `scale(${currentScale})`;
188                        currentImg.style.opacity = '1';
189                        requestAnimationFrame(() => {
190                            currentImg.style.opacity = '0';
191                            currentImg.style.transform = 'scale(0.98)';
192                        });
193                    }
194
195                    nextImg.style.opacity = '0';
196                    nextImg.style.transform = 'scale(1)';
197                    requestAnimationFrame(() => {
198                        nextImg.style.opacity = '1';
199                        nextImg.style.transform = 'scale(1)';
200                    });
201                });
202
203                setTimeout(() => {
204                    currentImg.className = 'image-layer';
205                    currentImg.style.cssText = '';
206                    nextImg.className = 'image-layer active';
207                    nextImg.style.cssText = '';
208                    currentLayer = nextLayer;
209                    isTransitioning = false;
210                }, 2500);
211
212            } catch (error) {
213                console.error(error);
214                loading.textContent = error.message;
215                isTransitioning = false;
216                setTimeout(changeImage, 2000);
217            }
218        }
219
220        async function initFirstImage() {
221            // 先从API获取图片列表
222            images = await fetchImageList();
223            
224            if (images.length === 0) {
225                loading.textContent = 'images目录中未找到图片';
226                return;
227            }
228            
229            const firstSrc = images[Math.floor(Math.random() * images.length)];
230            try {
231                await preloadImage(firstSrc);
232                await adjustImageDisplay(image1, firstSrc);
233                image1.src = firstSrc;
234                setTimeout(() => {
235                    image1.className = 'image-layer active';
236                    loading.style.opacity = '0';
237                    setTimeout(() => loading.style.display = 'none', 500);
238                }, 300);
239            } catch (error) {
240                console.error('初始化图片失败:', error);
241                loading.textContent = error.message;
242                setTimeout(initFirstImage, 2000);
243            }
244        }
245
246        function changeImage() {
247            if (images.length === 0) {
248                clearInterval(imageInterval);
249                return;
250            }
251            const randomSrc = images[Math.floor(Math.random() * images.length)];
252            fadeToNewImage(randomSrc);
253        }
254
255        // 初始化
256        initFirstImage();
257        
258        // 定时切换
259        imageInterval = setInterval(changeImage, 15000);
260        
261        // 每60秒刷新一次图片列表(支持动态添加新图片)
262        setInterval(async () => {
263            const newImages = await fetchImageList();
264            if (newImages.length > 0) {
265                images = newImages;
266                // 如果之前没有图片,现在有了就重新开始轮播
267                if (!imageInterval) {
268                    imageInterval = setInterval(changeImage, 15000);
269                    loading.style.display = 'none';
270                    initFirstImage();
271                }
272            } else {
273                clearInterval(imageInterval);
274                imageInterval = null;
275                loading.style.display = 'block';
276                loading.textContent = 'images目录中未找到图片';
277            }
278        }, 60000);
279    </script>
280</body>
281</html>
282    

📌后端代码(Go)

需要在你的 Go 项目中添加一个 API 接口,用于扫描images目录并返回图片路径列表:

Go图片扫描API

V1

创建时间:07:59

 1package main
 2
 3import (
 4	"encoding/json"
 5	"net/http"
 6	"os"
 7	"path/filepath"
 8	"strings"
 9)
10
11// 图片文件扩展名
12var imageExtensions = map[string]bool{
13	".jpg":  true,
14	".jpeg": true,
15	".png":  true,
16	".gif":  true,
17	".bmp":  true,
18	".webp": true,
19}
20
21// 扫描images目录下的所有图片
22func scanImages() ([]string, error) {
23	var images []string
24	root := "images" // 图片目录
25
26	// 检查目录是否存在
27	if _, err := os.Stat(root); os.IsNotExist(err) {
28		return images, nil // 目录不存在返回空列表
29	}
30
31	// 遍历目录
32	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
33		if err != nil {
34			return err
35		}
36
37		// 只处理文件
38		if !info.IsDir() {
39			ext := strings.ToLower(filepath.Ext(path))
40			// 检查是否为图片文件
41			if imageExtensions[ext] {
42				images = append(images, path)
43			}
44		}
45		return nil
46	})
47
48	return images, err
49}
50
51// API处理器:返回图片列表
52func imagesHandler(w http.ResponseWriter, r *http.Request) {
53	images, err := scanImages()
54	if err != nil {
55		http.Error(w, "扫描图片失败: "+err.Error(), http.StatusInternalServerError)
56		return
57	}
58
59	// 设置响应头为JSON
60	w.Header().Set("Content-Type", "application/json")
61	json.NewEncoder(w).Encode(map[string]interface{}{
62		"images": images,
63	})
64}
65
66func main() {
67	// 静态文件服务:提供HTML和图片访问
68	http.Handle("/", http.FileServer(http.Dir(".")))
69	
70	// 图片列表API
71	http.HandleFunc("/api/images", imagesHandler)
72
73	// 启动服务器
74	http.ListenAndServe(":8080", nil)
75}
76    

📌实现原理

  1. 后端(Go)
    • 创建/api/images接口,使用filepath.Walk扫描images目录
    • 过滤出图片格式文件(支持 jpg、png、gif 等常见格式)
    • 以 JSON 格式返回图片路径列表
  2. 前端(JavaScript)
    • 页面加载时通过fetch('/api/images')获取图片列表
    • 每 60 秒自动刷新一次图片列表,支持动态添加新图片
    • 无需手动维护images数组,完全自动获取

📌使用方法

  1. 将 HTML 文件放在项目根目录
  2. 创建images目录并放入图片
  3. 运行 Go 程序:go run main.go
  4. 访问http://localhost:8080即可看到自动加载的图片轮播

这样,你只需将图片放入images目录,无需修改任何代码,轮播会自动识别并加载新图片。

推荐使用微信支付
微信支付二维码
推荐使用支付宝
支付宝二维码
最新文章

文档导航