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:4 或 9: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,横屏可灵活切换(根据需求调整) |
| 用户体验 | 加载时无提示,失败无反馈 | 增加加载中提示,失败自动重试,优化错误文案 |
📌额外建议(根据实际场景选择)
- 如果希望横屏图片填满容器:
在
adjustImageDisplay函数中,将横屏图片(imgRatio > 1)的objectFit改回cover,竖屏图片保持contain,实现 “横屏填充满,竖屏保完整”。 - 如果图片尺寸差异过大:
可在后端接口
/api/images中返回图片宽高比信息,前端直接使用,减少前端临时计算的性能消耗。 - 增加图片居中裁剪(折中方案):
若
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的。
存在问题
人像照片可以正常显示了,但是两边出现了黑框。

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>
📌主要修改说明
- 毛玻璃边框实现:
- 使用
.image-container的::before和::after伪元素创建左右边框 - 通过
backdrop-filter: blur(10px)实现高斯模糊效果 - 配合渐变背景
linear-gradient实现从模糊到透明的过渡,使边框更自然
- 使用
- 背景增强:
- 添加了一张固定背景图,增强毛玻璃效果的层次感
- 毛玻璃效果会模糊其下方的背景内容,创造深度感
- 细节优化:
- 图片设置轻微透明(
opacity: 0.98),让背景能轻微渗透,增强融合感 - 加载提示也添加了轻微的毛玻璃效果,保持风格统一
- 调整了毛玻璃的透明度和模糊程度,确保效果美观且不影响图片主体观看
- 图片设置轻微透明(
- 兼容性考虑:
- 添加了
-webkit-backdrop-filter前缀以支持 WebKit 内核浏览器 - 毛玻璃效果在不支持的浏览器中会自动降级为半透明效果
- 添加了
你可以通过调整这些值来优化效果:
- 边框宽度:修改
.image-container::before和::after的width属性 - 模糊程度:调整
backdrop-filter: blur(10px)中的像素值 - 边框透明度:修改渐变中的
rgba(255, 255, 255, 0.15)的 alpha 值
这种毛玻璃效果能很好地解决图片两侧空白区域的视觉问题,同时增添现代感和高级感。
效果测试(存在问题)

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>
📌关键修改说明
- 图片路径调整:
- 将
images数组中的图片路径修改为本地路径格式:'images/文件名' - 请务必将示例中的
photo1.jpg等替换为你实际的图片文件名
- 将
- 本地适配优化:
- 注释掉了从远程 API 获取图片列表的代码,因为我们使用本地图片
- 背景从在线图片改为深色纯色背景,避免与本地图片风格冲突
- 错误处理增强:
- 新增了
checkImageExists函数,专门检查本地图片是否存在 - 错误提示中会显示具体的图片路径,方便你排查路径问题
- 新增了
- 毛玻璃效果调整:
- 边框颜色从白色系改为深色系(
rgba(0, 0, 0, 0.3)),更适合本地图片展示
- 边框颜色从白色系改为深色系(
📌排查本地图片不显示的常见问题
- 路径是否正确:
- 确保你的 HTML 文件和
images目录在同一级目录 - 例如:
index.html和images文件夹平级,图片放在images里
- 确保你的 HTML 文件和
- 文件名是否正确:
- 注意文件名的大小写(尤其是在 Linux/macOS 系统)
- 扩展名是否正确(是
jpg还是jpeg,png还是gif)
- 文件权限问题:
- 确保图片文件有可读权限
如果仍然无法显示,可以打开浏览器的开发者工具(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 无法直接访问本地文件系统)。以下是一个前后端结合的解决方案:
📌实现思路
- 后端(Go)提供一个 API 接口,用于扫描
images目录并返回所有图片路径 - 前端通过这个 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
📌实现原理
- 后端(Go):
- 创建
/api/images接口,使用filepath.Walk扫描images目录 - 过滤出图片格式文件(支持 jpg、png、gif 等常见格式)
- 以 JSON 格式返回图片路径列表
- 创建
- 前端(JavaScript):
- 页面加载时通过
fetch('/api/images')获取图片列表 - 每 60 秒自动刷新一次图片列表,支持动态添加新图片
- 无需手动维护
images数组,完全自动获取
- 页面加载时通过
📌使用方法
- 将 HTML 文件放在项目根目录
- 创建
images目录并放入图片 - 运行 Go 程序:
go run main.go - 访问
http://localhost:8080即可看到自动加载的图片轮播
这样,你只需将图片放入images目录,无需修改任何代码,轮播会自动识别并加载新图片。

