跳到主要内容

图片查看器美化

最后更新于:

图片查看器美化

image-20251102203218272

目录

[[toc]]

[toc]

版权

次功能来自《白木》大佬,感谢大佬。❤️❤️❤️

环境

Teek@1.5.1-2025.10.19版本

Teek-one开箱即用版仓库:https://cnb.cool/onedayxyy/vitepress-theme-teek-one-public

背景

白木大佬美化了teek的图片查看器,那么我这里更新一篇文章出来哦,感谢白木大佬。💖💖💖

效果

之前效果:

PixPin_2025-11-02_20-21-06

美化后效果:

image-20251102202718978

配置

(1)新建docs\.vitepress\theme\style\dd-image目录,再在此目录下新建如下2个文件:

docs\.vitepress\theme\style\dd-image\dd-image.scss文件:

  1// 图片查看器样式 - 基于原版美化
  2body .tk-image-viewer__wrapper {
  3  position: fixed;
  4  top: 0;
  5  left: 0;
  6  width: 100%;
  7  height: 100%;
  8  background-color: rgba(0, 0, 0, 0.9);
  9  display: flex;
 10  justify-content: center;
 11  align-items: center;
 12  z-index: 9999;
 13  cursor: pointer;
 14  animation: fadeIn 0.3s ease;
 15}
 16
 17// 图片容器样式
 18body .tk-image-viewer__wrapper .tk-image-viewer__canvas {
 19  max-width: 90%;
 20  max-height: 80%;
 21  display: flex;
 22  justify-content: center;
 23  align-items: center;
 24  cursor: grab;
 25  border-radius: 16px;
 26  overflow: visible;
 27  position: relative;
 28}
 29
 30// 拖拽时的光标样式
 31body .tk-image-viewer__wrapper .tk-image-viewer__canvas:active {
 32  cursor: grabbing;
 33}
 34
 35// 图片样式
 36body .tk-image-viewer__wrapper .tk-image-viewer__canvas img {
 37  max-width: 100%;
 38  max-height: 100%;
 39  object-fit: contain;
 40  transition:
 41    opacity 0.2s ease,
 42    transform 0.3s ease,
 43    border-radius 0.3s ease;
 44  transform: none;
 45  border-radius: 16px;
 46  position: relative;
 47  cursor: inherit;
 48}
 49
 50// 关闭按钮样式
 51body .tk-image-viewer__wrapper .tk-image-viewer__close {
 52  position: absolute;
 53  top: 20px;
 54  right: 20px;
 55  background: rgba(0, 47, 255, 0.582);
 56  border: 2px solid rgba(0, 255, 242, 0.3);
 57  border-radius: 50%;
 58  padding: 12px;
 59  font-size: 20px;
 60  color: white;
 61  cursor: pointer;
 62  transition: all 0.3s ease;
 63  display: flex;
 64  justify-content: center;
 65  align-items: center;
 66  z-index: 1000;
 67}
 68
 69// 关闭按钮悬停效果
 70body .tk-image-viewer__wrapper .tk-image-viewer__close:hover {
 71  background: rgba(255, 0, 234, 0.5);
 72  transform: scale(1.1);
 73}
 74
 75// 关闭按钮聚焦效果
 76body .tk-image-viewer__wrapper .tk-image-viewer__close:focus {
 77  outline: none;
 78  box-shadow: 0 0 0 3px rgba(255, 0, 234, 0.5);
 79}
 80
 81// 关闭按钮图标样式
 82body .tk-image-viewer__wrapper .tk-image-viewer__close .tk-icon {
 83  color: rgb(255, 255, 255);
 84  font-size: 20px;
 85  line-height: 1;
 86}
 87
 88// 图片缩放按钮容器样式
 89body .tk-image-viewer__wrapper .tk-image-viewer__actions {
 90  position: absolute;
 91  left: 50%;
 92  bottom: 30px;
 93  transform: translateX(-50%);
 94  background: rgba(0, 0, 0, 0.7);
 95  border-radius: 30px;
 96  padding: 10px 20px;
 97  display: flex;
 98  gap: 10px;
 99  flex-wrap: nowrap;
100  justify-content: center;
101  align-items: center;
102  min-width: fit-content;
103  white-space: nowrap;
104  overflow: visible;
105  z-index: 100;
106}
107
108body .tk-image-viewer__wrapper .tk-image-viewer__actions::-webkit-scrollbar {
109  display: none;
110}
111
112// 底部的功能按钮样式
113body .tk-image-viewer__wrapper .tk-image-viewer__btn {
114  background: rgba(0, 38, 255, 0.1); // 背景色
115  border: 2px solid rgba(0, 204, 255, 0.295); // 边框颜色
116  border-radius: 50%;
117  padding: 8px;
118  width: 36px;
119  height: 36px;
120  font-size: 16px;
121  color: white;
122  cursor: pointer;
123  transition: all 0.3s ease;
124  display: flex;
125  align-items: center;
126  justify-content: center;
127  flex-shrink: 0;
128  position: relative;
129  z-index: 1;
130}
131
132// 缩放按钮样式
133body .tk-image-viewer__wrapper .tk-image-viewer__zoom {
134  @extend .tk-image-viewer__btn;
135}
136
137// 按钮悬停效果
138body .tk-image-viewer__wrapper .tk-image-viewer__btn:hover,
139body .tk-image-viewer__wrapper .tk-image-viewer__zoom:hover {
140  background: rgba(255, 0, 234, 0.5);
141  transform: scale(1.1);
142}
143
144// 按钮聚焦效果
145body .tk-image-viewer__wrapper .tk-image-viewer__btn:focus,
146body .tk-image-viewer__wrapper .tk-image-viewer__zoom:focus {
147  outline: none;
148  box-shadow: 0 0 0 3px rgba(255, 0, 234, 0.5);
149}
150
151// 按钮点击激活状态
152body .tk-image-viewer__wrapper .tk-image-viewer__btn--active {
153  transform: scale(0.95);
154  background: rgba(255, 0, 234, 0.5);
155}
156
157// 缩放按钮点击激活状态
158body .tk-image-viewer__wrapper .tk-image-viewer__zoom--active {
159  transform: scale(0.95);
160  background: rgba(255, 0, 234, 0.5);
161}
162
163// 缩放按钮激活状态图标样式
164body .tk-image-viewer__wrapper .tk-image-viewer__zoom--active .tk-icon {
165  color: #4caf50;
166}
167
168// 图标样式
169body .tk-image-viewer__wrapper .tk-icon {
170  font-size: inherit;
171  display: flex;
172  align-items: center;
173  justify-content: center;
174  font-style: normal !important;
175  color: white;
176  line-height: 1;
177  margin: 0;
178  padding: 0;
179  font-family: inherit;
180  font-weight: inherit;
181  text-align: center;
182  vertical-align: middle;
183  max-width: 100%;
184  max-height: 100%;
185  vertical-align: baseline;
186}
187
188// 图片计数样式
189body .tk-image-viewer__wrapper .tk-image-viewer__info {
190  position: absolute;
191  bottom: 100px;
192  left: 50%;
193  transform: translateX(-50%);
194  background: rgba(0, 0, 0, 0.7);
195  color: white;
196  padding: 8px 16px;
197  border-radius: 20px;
198  font-size: 14px;
199  font-family: Arial, sans-serif;
200  min-width: 60px;
201  text-align: center;
202}
203
204// 动画样式
205@keyframes fadeIn {
206  from {
207    opacity: 0;
208  }
209  to {
210    opacity: 1;
211  }
212}
213
214@keyframes fadeOut {
215  from {
216    opacity: 1;
217  }
218  to {
219    opacity: 0;
220  }
221}
222
223// 淡出动画类
224body .tk-image-viewer__wrapper--fade-out {
225  animation: fadeOut 0.3s ease;
226}
227
228// 响应式
229@media (max-width: 768px) {
230  body .tk-image-viewer__wrapper .tk-image-viewer__canvas {
231    cursor: grab;
232  }
233
234  body .tk-image-viewer__wrapper .tk-image-viewer__canvas:active {
235    cursor: grabbing;
236  }
237
238  body .tk-image-viewer__wrapper .tk-image-viewer__actions {
239    gap: 10px;
240    padding: 8px 15px;
241    bottom: 20px;
242  }
243
244  body .tk-image-viewer__wrapper .tk-image-viewer__btn,
245  body .tk-image-viewer__wrapper .tk-image-viewer__zoom {
246    padding: 8px;
247    font-size: 18px;
248    min-width: 36px;
249    min-height: 36px;
250  }
251
252  body .tk-image-viewer__wrapper .tk-image-viewer__close {
253    padding: 10px;
254    font-size: 18px;
255    top: 15px;
256    right: 15px;
257  }
258
259  body .tk-image-viewer__wrapper .tk-image-viewer__info {
260    bottom: 80px;
261    font-size: 12px;
262    padding: 6px 12px;
263  }
264}

docs\.vitepress\theme\style\dd-image\dd-image.ts文件:

  1// 图片查看器功能实现
  2// 图片查看器类
  3class ImageViewer {
  4  private viewerWrapper: HTMLElement | null = null;
  5  private canvas: HTMLElement | null = null;
  6  private closeBtn: HTMLElement | null = null;
  7  private rotateBtn: HTMLElement | null = null;
  8  private prevBtn: HTMLElement | null = null;
  9  private nextBtn: HTMLElement | null = null;
 10  private fullScreenBtn: HTMLElement | null = null;
 11  private originalSizeBtn: HTMLElement | null = null;
 12  private zoomInBtn: HTMLElement | null = null;
 13  private zoomOutBtn: HTMLElement | null = null;
 14  private currentImg: HTMLImageElement | null = null;
 15  private imgList: string[] = [];
 16  private currentIndex: number = 0;
 17  private scale: number = 1;
 18  private rotation: number = 0;
 19  private isFullScreen: boolean = false;
 20  private isDragging: boolean = false;
 21  private dragStartX: number = 0;
 22  private dragStartY: number = 0;
 23  private translateX: number = 0;
 24  private translateY: number = 0;
 25
 26  constructor() {
 27    this.init();
 28  }
 29
 30  private init() {
 31    if (typeof window === "undefined") return;
 32
 33    if (document.readyState === "loading") {
 34      document.addEventListener("DOMContentLoaded", this.setupImageListeners.bind(this));
 35    } else {
 36      this.setupImageListeners();
 37    }
 38
 39    this.observeDOMChanges();
 40  }
 41
 42  private setupImageListeners() {
 43    const vpDocElement = document.querySelector(".vp-doc");
 44    if (vpDocElement) {
 45      const images = vpDocElement.querySelectorAll("img:not(.tk-image-viewer__canvas img)");
 46      images.forEach(img => {
 47        const htmlImg = img as HTMLImageElement;
 48        if (!htmlImg.dataset.imageViewerInitialized) {
 49          htmlImg.dataset.imageViewerInitialized = "true";
 50          htmlImg.style.cursor = "pointer";
 51          htmlImg.addEventListener("click", (e: MouseEvent) => this.handleImageClick(e, htmlImg));
 52        }
 53      });
 54    }
 55  }
 56
 57  private observeDOMChanges() {
 58    const observer = new MutationObserver(() => {
 59      this.setupImageListeners();
 60    });
 61
 62    observer.observe(document.body, {
 63      childList: true,
 64      subtree: true,
 65    });
 66  }
 67
 68  private handleImageClick(event: MouseEvent, img: HTMLImageElement) {
 69    event.stopPropagation();
 70
 71    this.collectImages();
 72    this.currentIndex = this.imgList.findIndex(src => src === img.src);
 73
 74    this.createViewer(img.src);
 75  }
 76
 77  // 只收集内容区域中的图片
 78  private collectImages() {
 79    this.imgList = [];
 80    const vpDocElement = document.querySelector(".vp-doc");
 81    if (vpDocElement) {
 82      const images = vpDocElement.querySelectorAll("img:not(.tk-image-viewer__canvas img)");
 83      images.forEach(img => {
 84        this.imgList.push((img as HTMLImageElement).src);
 85      });
 86    }
 87  }
 88
 89  private createViewer(src: string) {
 90    this.removeViewer();
 91
 92    this.viewerWrapper = document.createElement("div");
 93    this.viewerWrapper.className = "tk-image-viewer__wrapper";
 94
 95    this.canvas = document.createElement("div");
 96    this.canvas.className = "tk-image-viewer__canvas";
 97
 98    const viewerImg = document.createElement("img");
 99    viewerImg.src = src;
100    viewerImg.style.transform = "none";
101    this.currentImg = viewerImg;
102
103    this.closeBtn = document.createElement("button");
104    this.closeBtn.className = "tk-image-viewer__close";
105    this.closeBtn.innerHTML = '<i class="tk-icon">❌</i>';
106
107    const actionsContainer = document.createElement("div");
108    actionsContainer.className = "tk-image-viewer__actions";
109
110    this.rotateBtn = document.createElement("button");
111    this.rotateBtn.className = "tk-image-viewer__btn";
112    this.rotateBtn.innerHTML = '<i class="tk-icon">🔄</i>';
113
114    this.prevBtn = document.createElement("button");
115    this.prevBtn.className = "tk-image-viewer__btn";
116    this.prevBtn.innerHTML = '<i class="tk-icon">⬅️</i>';
117
118    this.zoomOutBtn = document.createElement("button");
119    this.zoomOutBtn.className = "tk-image-viewer__btn";
120    this.zoomOutBtn.innerHTML = '<i class="tk-icon">➖</i>';
121
122    this.fullScreenBtn = document.createElement("button");
123    this.fullScreenBtn.className = "tk-image-viewer__btn";
124    this.fullScreenBtn.innerHTML = '<i class="tk-icon">🔳</i>';
125
126    this.originalSizeBtn = document.createElement("button");
127    this.originalSizeBtn.className = "tk-image-viewer__btn";
128    this.originalSizeBtn.innerHTML = '<i class="tk-icon">🔍</i>';
129
130    this.zoomInBtn = document.createElement("button");
131    this.zoomInBtn.className = "tk-image-viewer__btn";
132    this.zoomInBtn.innerHTML = '<i class="tk-icon">➕</i>';
133
134    this.nextBtn = document.createElement("button");
135    this.nextBtn.className = "tk-image-viewer__btn";
136    this.nextBtn.innerHTML = '<i class="tk-icon">➡️</i>';
137
138    // 🚀底部功能操作按钮排序
139    actionsContainer.appendChild(this.prevBtn);
140    actionsContainer.appendChild(this.nextBtn);
141    actionsContainer.appendChild(this.zoomInBtn);
142    actionsContainer.appendChild(this.zoomOutBtn);
143    actionsContainer.appendChild(this.fullScreenBtn);
144    actionsContainer.appendChild(this.rotateBtn);
145    actionsContainer.appendChild(this.originalSizeBtn);
146
147    const infoContainer = document.createElement("div");
148    infoContainer.className = "tk-image-viewer__info";
149    infoContainer.textContent = `${this.currentIndex + 1} / ${this.imgList.length}`;
150    (this.viewerWrapper as any).infoContainer = infoContainer;
151
152    this.canvas.appendChild(viewerImg);
153    this.viewerWrapper.appendChild(this.canvas);
154    this.viewerWrapper.appendChild(this.closeBtn);
155    this.viewerWrapper.appendChild(actionsContainer);
156    this.viewerWrapper.appendChild(infoContainer);
157
158    document.body.appendChild(this.viewerWrapper);
159
160    this.addViewerEventListeners(viewerImg);
161  }
162
163  private addViewerEventListeners(img: HTMLImageElement) {
164    if (!this.viewerWrapper || !this.canvas || !this.closeBtn) return;
165
166    this.scale = 1;
167    this.rotation = 0;
168    this.isFullScreen = false;
169
170    const scaleStep = 0.1;
171    const maxScale = 3;
172    const minScale = 0.5;
173    const rotateStep = 90;
174
175    const updateTransform = () => {
176      img.style.transform = `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale}) rotate(${this.rotation}deg)`;
177    };
178
179    img.addEventListener("click", (e: MouseEvent) => {
180      e.stopPropagation();
181    });
182
183    const handleDragStart = (e: MouseEvent) => {
184      e.stopPropagation();
185      this.isDragging = true;
186      this.dragStartX = e.clientX - this.translateX;
187      this.dragStartY = e.clientY - this.translateY;
188      document.body.style.userSelect = "none";
189    };
190
191    const handleDragMove = (e: MouseEvent) => {
192      if (!this.isDragging) return;
193      this.translateX = e.clientX - this.dragStartX;
194      this.translateY = e.clientY - this.dragStartY;
195      updateTransform();
196    };
197
198    const handleDragEnd = () => {
199      this.isDragging = false;
200      document.body.style.userSelect = "";
201    };
202
203    img.addEventListener("mousedown", handleDragStart);
204    document.addEventListener("mousemove", handleDragMove);
205    document.addEventListener("mouseup", handleDragEnd);
206    document.addEventListener("mouseleave", handleDragEnd);
207
208    const handleTouchStart = (e: TouchEvent) => {
209      const touch = e.touches[0];
210      e.stopPropagation();
211      this.isDragging = true;
212      this.dragStartX = touch.clientX - this.translateX;
213      this.dragStartY = touch.clientY - this.translateY;
214      document.body.style.userSelect = "none";
215    };
216
217    const handleTouchMove = (e: TouchEvent) => {
218      if (!this.isDragging || e.touches.length !== 1) return;
219      const touch = e.touches[0];
220      this.translateX = touch.clientX - this.dragStartX;
221      this.translateY = touch.clientY - this.dragStartY;
222      updateTransform();
223    };
224
225    const handleTouchEnd = () => {
226      this.isDragging = false;
227      document.body.style.userSelect = "";
228    };
229
230    img.addEventListener("touchstart", handleTouchStart, { passive: false });
231    document.addEventListener("touchmove", handleTouchMove, { passive: false });
232    document.addEventListener("touchend", handleTouchEnd);
233    document.addEventListener("touchcancel", handleTouchEnd);
234
235    this.viewerWrapper.addEventListener("click", () => {
236      this.removeViewer();
237    });
238
239    this.closeBtn.addEventListener("click", (e: MouseEvent) => {
240      e.stopPropagation();
241      this.removeViewer();
242    });
243
244    if (this.rotateBtn) {
245      const rotateBtnRef = this.rotateBtn;
246      this.rotateBtn.addEventListener("click", (e: MouseEvent) => {
247        e.stopPropagation();
248        this.rotation = (this.rotation + rotateStep) % 360;
249        updateTransform();
250        rotateBtnRef.classList.add("tk-image-viewer__btn--active");
251        setTimeout(() => {
252          rotateBtnRef.classList.remove("tk-image-viewer__btn--active");
253        }, 200);
254      });
255    }
256
257    this.prevBtn!.addEventListener("click", (e: MouseEvent) => {
258      e.stopPropagation();
259      if (this.imgList.length > 1) {
260        this.currentIndex = (this.currentIndex - 1 + this.imgList.length) % this.imgList.length;
261        this.switchImage(this.imgList[this.currentIndex]);
262        this.prevBtn!.classList.add("tk-image-viewer__btn--active");
263        setTimeout(() => {
264          this.prevBtn!.classList.remove("tk-image-viewer__btn--active");
265        }, 200);
266      }
267    });
268
269    this.nextBtn!.addEventListener("click", (e: MouseEvent) => {
270      e.stopPropagation();
271      if (this.imgList.length > 1) {
272        this.currentIndex = (this.currentIndex + 1) % this.imgList.length;
273        this.switchImage(this.imgList[this.currentIndex]);
274        this.nextBtn!.classList.add("tk-image-viewer__btn--active");
275        setTimeout(() => {
276          this.nextBtn!.classList.remove("tk-image-viewer__btn--active");
277        }, 200);
278      }
279    });
280
281    if (this.fullScreenBtn) {
282      const fullScreenBtnRef = this.fullScreenBtn;
283      this.fullScreenBtn.addEventListener("click", (e: MouseEvent) => {
284        e.stopPropagation();
285        this.isFullScreen = !this.isFullScreen;
286        if (this.isFullScreen) {
287          img.style.maxWidth = "none";
288          img.style.maxHeight = "none";
289          fullScreenBtnRef.innerHTML = '<i class="tk-icon">🔲</i>';
290        } else {
291          img.style.maxWidth = "100%";
292          img.style.maxHeight = "100%";
293          fullScreenBtnRef.innerHTML = '<i class="tk-icon">🔳</i>';
294        }
295        fullScreenBtnRef.classList.add("tk-image-viewer__btn--active");
296        setTimeout(() => {
297          fullScreenBtnRef.classList.remove("tk-image-viewer__btn--active");
298        }, 200);
299      });
300    }
301
302    if (this.originalSizeBtn) {
303      const originalSizeBtnRef = this.originalSizeBtn;
304      this.originalSizeBtn.addEventListener("click", (e: MouseEvent) => {
305        e.stopPropagation();
306        this.scale = 1;
307        this.rotation = 0;
308        this.translateX = 0;
309        this.translateY = 0;
310        updateTransform();
311        originalSizeBtnRef.classList.add("tk-image-viewer__btn--active");
312        setTimeout(() => {
313          originalSizeBtnRef.classList.remove("tk-image-viewer__btn--active");
314        }, 200);
315      });
316    }
317
318    if (this.zoomInBtn) {
319      const zoomInBtnRef = this.zoomInBtn;
320      this.zoomInBtn.addEventListener("click", (e: MouseEvent) => {
321        e.stopPropagation();
322        if (this.scale < maxScale) {
323          this.scale += scaleStep;
324          updateTransform();
325          zoomInBtnRef.classList.add("tk-image-viewer__btn--active");
326          setTimeout(() => {
327            zoomInBtnRef.classList.remove("tk-image-viewer__btn--active");
328          }, 200);
329        }
330      });
331    }
332
333    if (this.zoomOutBtn) {
334      const zoomOutBtnRef = this.zoomOutBtn;
335      this.zoomOutBtn.addEventListener("click", (e: MouseEvent) => {
336        e.stopPropagation();
337        if (this.scale > minScale) {
338          this.scale -= scaleStep;
339          updateTransform();
340          zoomOutBtnRef.classList.add("tk-image-viewer__btn--active");
341          setTimeout(() => {
342            zoomOutBtnRef.classList.remove("tk-image-viewer__btn--active");
343          }, 200);
344        }
345      });
346    }
347
348    const handleKeydown = (e: KeyboardEvent) => {
349      e.preventDefault();
350
351      switch (e.key) {
352        case "Escape":
353          this.removeViewer();
354          break;
355        case "+":
356        case "=":
357          if (this.scale < maxScale) {
358            this.scale += scaleStep;
359            updateTransform();
360          }
361          break;
362        case "-":
363          if (this.scale > minScale) {
364            this.scale -= scaleStep;
365            updateTransform();
366          }
367          break;
368        case "r":
369        case "R":
370          this.rotation = (this.rotation + rotateStep) % 360;
371          updateTransform();
372          break;
373        case "ArrowLeft":
374          if (this.imgList.length > 1) {
375            this.currentIndex = (this.currentIndex - 1 + this.imgList.length) % this.imgList.length;
376            this.switchImage(this.imgList[this.currentIndex]);
377          }
378          break;
379        case "ArrowRight":
380          if (this.imgList.length > 1) {
381            this.currentIndex = (this.currentIndex + 1) % this.imgList.length;
382            this.switchImage(this.imgList[this.currentIndex]);
383          }
384          break;
385        case "0":
386          this.scale = 1;
387          this.rotation = 0;
388          this.translateX = 0;
389          this.translateY = 0;
390          updateTransform();
391          break;
392        case "f":
393        case "F":
394          this.isFullScreen = !this.isFullScreen;
395          if (this.isFullScreen) {
396            img.style.maxWidth = "none";
397            img.style.maxHeight = "none";
398            if (this.fullScreenBtn) {
399              this.fullScreenBtn.innerHTML = '<i class="tk-icon">🔲</i>';
400            }
401          } else {
402            img.style.maxWidth = "100%";
403            img.style.maxHeight = "100%";
404            if (this.fullScreenBtn) {
405              this.fullScreenBtn.innerHTML = '<i class="tk-icon">🔳</i>';
406            }
407          }
408          break;
409      }
410    };
411
412    document.addEventListener("keydown", handleKeydown);
413
414    const handleWheel = (e: WheelEvent) => {
415      e.preventDefault();
416      if (e.deltaY < 0 && this.scale < maxScale) {
417        this.scale += scaleStep;
418        updateTransform();
419      } else if (e.deltaY > 0 && this.scale > minScale) {
420        this.scale -= scaleStep;
421        updateTransform();
422      }
423    };
424
425    this.viewerWrapper.addEventListener("wheel", handleWheel, { passive: false });
426
427    (this.viewerWrapper as any).keydownHandler = handleKeydown;
428    (this.viewerWrapper as any).wheelHandler = handleWheel;
429    (this.viewerWrapper as any).dragStartHandler = handleDragStart;
430    (this.viewerWrapper as any).dragMoveHandler = handleDragMove;
431    (this.viewerWrapper as any).dragEndHandler = handleDragEnd;
432    (this.viewerWrapper as any).touchStartHandler = handleTouchStart;
433    (this.viewerWrapper as any).touchMoveHandler = handleTouchMove;
434    (this.viewerWrapper as any).touchEndHandler = handleTouchEnd;
435  }
436
437  private switchImage(newSrc: string) {
438    if (!this.currentImg || !this.viewerWrapper) return;
439
440    this.currentImg.style.opacity = "0";
441
442    setTimeout(() => {
443      if (this.currentImg) {
444        this.currentImg.src = newSrc;
445        this.currentImg.style.opacity = "1";
446        this.currentImg.style.transform = `scale(${this.scale}) rotate(${this.rotation}deg)`;
447        if (this.isFullScreen) {
448          this.currentImg.style.maxWidth = "none";
449          this.currentImg.style.maxHeight = "none";
450        } else {
451          this.currentImg.style.maxWidth = "100%";
452          this.currentImg.style.maxHeight = "100%";
453        }
454      }
455
456      const infoContainer = (this.viewerWrapper as any).infoContainer;
457      if (infoContainer) {
458        infoContainer.textContent = `${this.currentIndex + 1} / ${this.imgList.length}`;
459      }
460    }, 200);
461  }
462
463  private removeViewer() {
464    if (this.viewerWrapper) {
465      const keydownHandler = (this.viewerWrapper as any).keydownHandler;
466      const wheelHandler = (this.viewerWrapper as any).wheelHandler;
467      const dragStartHandler = (this.viewerWrapper as any).dragStartHandler;
468      const dragMoveHandler = (this.viewerWrapper as any).dragMoveHandler;
469      const dragEndHandler = (this.viewerWrapper as any).dragEndHandler;
470      const touchStartHandler = (this.viewerWrapper as any).touchStartHandler;
471      const touchMoveHandler = (this.viewerWrapper as any).touchMoveHandler;
472      const touchEndHandler = (this.viewerWrapper as any).touchEndHandler;
473
474      if (keydownHandler) {
475        document.removeEventListener("keydown", keydownHandler);
476      }
477      if (wheelHandler) {
478        this.viewerWrapper.removeEventListener("wheel", wheelHandler);
479      }
480      if (dragStartHandler && this.currentImg) {
481        this.currentImg.removeEventListener("mousedown", dragStartHandler);
482      }
483      if (dragMoveHandler) {
484        document.removeEventListener("mousemove", dragMoveHandler);
485      }
486      if (dragEndHandler) {
487        document.removeEventListener("mouseup", dragEndHandler);
488        document.removeEventListener("mouseleave", dragEndHandler);
489      }
490      if (touchStartHandler && this.currentImg) {
491        this.currentImg.removeEventListener("touchstart", touchStartHandler);
492      }
493      if (touchMoveHandler) {
494        document.removeEventListener("touchmove", touchMoveHandler);
495      }
496      if (touchEndHandler) {
497        document.removeEventListener("touchend", touchEndHandler);
498        document.removeEventListener("touchcancel", touchEndHandler);
499      }
500      document.body.style.userSelect = "";
501
502      this.viewerWrapper.classList.add("tk-image-viewer__wrapper--fade-out");
503
504      setTimeout(() => {
505        if (this.viewerWrapper && this.viewerWrapper.parentNode) {
506          this.viewerWrapper.parentNode.removeChild(this.viewerWrapper);
507        }
508        this.viewerWrapper = null;
509        this.canvas = null;
510        this.closeBtn = null;
511        this.rotateBtn = null;
512        this.prevBtn = null;
513        this.nextBtn = null;
514        this.fullScreenBtn = null;
515        this.originalSizeBtn = null;
516        this.zoomInBtn = null;
517        this.zoomOutBtn = null;
518        this.currentImg = null;
519        this.imgList = [];
520        this.currentIndex = 0;
521        this.scale = 1;
522        this.rotation = 0;
523        this.isFullScreen = false;
524        this.isDragging = false;
525        this.translateX = 0;
526        this.translateY = 0;
527      }, 300);
528    }
529  }
530}
531
532// 所有样式已移至dd-image.scss
533
534export function initImageViewer() {
535  if (typeof window !== "undefined") {
536    new ImageViewer();
537  }
538}

(2)引入

编辑docs\.vitepress\theme\index.ts文件:

1import { initImageViewer } from "./style/dd-image/dd-image.ts" // 引入图片查看器功能(替换原版
2
3    // 🔽 替换原版图片查看器
4    initImageViewer();

具体文件,请查看开源库如下链接:

https://cnb.cool/onedayxyy/vitepress-theme-teek-one-public/-/blob/main/docs/.vitepress/theme/index.ts

编辑docs\.vitepress\theme\style\index.scss文件:

1@use "./dd-image/dd-image.scss" as *; // 引入图片查看器样式替换原版

(3)验证

image-20251102202718978

结束。

最新文章

文档导航