JavaScript 实现图片预览功能

502 阅读3分钟

本文介绍了一个基于 JavaScript 的图片预览功能,用户点击图片时可实现放大预览,同时支持滚轮缩放和居中显示效果。通过简单的配置,可以将此功能灵活集成到不同的项目中。


功能概述

该图片预览功能具备以下特性:

  • 图片点击放大:点击图片后,自动放大至屏幕中央,遮罩背景,提升用户沉浸感。
  • 滚轮缩放:支持鼠标滚轮对图片进行放大或缩小。
  • 居中显示:自动计算图片位置和缩放比例,使图片适配窗口并居中。
  • 关闭预览:点击遮罩层即可退出预览,恢复初始状态。
  • 链接优先支持:若图片嵌套在超链接中,则点击优先跳转,而不是触发预览功能。

功能实现

以下是功能的具体实现及逐步解析。


1. 初始化图片预览功能

通过 initialize 函数,将事件监听器绑定到目标图片上。当用户点击图片时,触发 handleImageClick 进行后续处理。

核心代码

function initialize(selector) {
  const targetDom = document.querySelectorAll(selector);
  if (targetDom.length > 0) {
    targetDom.forEach(item => item.addEventListener("click", handleImageClick));
  }
}

功能点

  • 参数 selector 接收一个 CSS 选择器,匹配所有目标图片。
  • 遍历目标图片,逐一绑定点击事件监听器。

2. 处理点击事件

点击图片时,检查图片是否嵌套在超链接中。如果存在超链接,则优先跳转,否则触发图片预览。

核心代码

function handleImageClick(e) {
  e.preventDefault();

  if (e.target.tagName === "IMG" && closest(e.target, "a")) {
    const link = closest(e.target, "a");
    const target = link.getAttribute("target") || "_self";
    const rel = link.getAttribute("rel") || "noopener";
    window.open(link.href, target, rel);
    return;
  }

  if (e.target.tagName === "IMG") {
    originalEl = e.target;
    cloneEl = originalEl.cloneNode(true);
    openPreview();
  }
}

功能点

  • closest 函数递归寻找图片的最近父级超链接节点。
  • 如果存在超链接,则根据其 href 和相关属性打开链接。
  • 否则,克隆图片并调用 openPreview 显示预览。

3. 显示图片预览

通过 openPreview 函数实现以下功能:

  1. 计算图片缩放比例和居中偏移。
  2. 创建遮罩层。
  3. 将图片居中并放大显示。

核心代码

function openPreview() {
  scale = 1;
  const { offsetWidth, offsetHeight } = originalEl;
  const { top, left } = originalEl.getBoundingClientRect();

  const mask = createMask();
  document.body.appendChild(mask);
  mask.addEventListener("click", () => closePreview(mask));
  mask.addEventListener("wheel", zoom, { passive: false });

  applyStyles(cloneEl, {
    position: "absolute",
    left: `${left}px`,
    top: `${top}px`,
    width: `${offsetWidth}px`,
    transform: "translateZ(0)",
  });
  mask.appendChild(cloneEl);

  moveToCenter(offsetWidth, offsetHeight, left, top);
}

功能点

  • 通过 getBoundingClientRect 获取图片位置和尺寸。
  • 动态创建遮罩层,添加关闭和缩放事件监听。
  • 调用 moveToCenter 方法,将图片移动到屏幕中央。

4. 创建遮罩层

遮罩层使图片预览更加突出,并阻止用户与页面其他内容交互。

核心代码

function createMask() {
  const mask = document.createElement("div");
  mask.classList.add(config.maskClass);
  applyStyles(mask, {
    position: "fixed",
    top: "0",
    left: "0",
    width: "100vw",
    height: "100vh",
    backgroundColor: "rgba(0, 0, 0, 0.75)",
    zIndex: 10000,
    userSelect: "none",
    touchAction: "none",
  });
  return mask;
}

功能点

  • 通过 applyStyles 设置遮罩层样式,使其全屏覆盖。
  • 提高层级显示,确保遮罩层在最顶层。

5. 图片居中显示

计算图片居中的偏移量,并通过动画效果将图片移动到屏幕中央。

核心代码

function moveToCenter(width, height, left, top) {
  const scaleToFit = adaptScale(width, height);
  const offsetCenter = calculateCenterOffset(width, height, left, top, scaleToFit);

  applyStyles(cloneEl, {
    transition: `all ${config.transitionDuration}ms`,
    width: `${width * scaleToFit}px`,
    transform: `translate(${offsetCenter.left}px, ${offsetCenter.top}px)`,
  });

  offset = offsetCenter;
  recordInitialData();
}

功能点

  • adaptScale 动态计算缩放比例,确保图片适配屏幕。
  • 调用 calculateCenterOffset 获取居中偏移量。
  • 使用 transition 属性实现平滑动画效果。

6. 鼠标滚轮缩放

通过鼠标滚轮调整图片大小,并确保缩放效果以鼠标为中心。

核心代码

function zoom(event) {
  event.preventDefault();
  scale = Math.min(Math.max(scale + (event.deltaY < 0 ? config.zoomStep : -config.zoomStep), config.minScale), 3);

  const offsetCorrection = getOffsetCorrection(event.offsetX, event.offsetY);
  applyStyles(cloneEl, {
    transform: `translate(${offsetCorrection.left}px, ${offsetCorrection.top}px) scale(${scale})`,
    transformOrigin: `${event.offsetX}px ${event.offsetY}px`,
  });
}

功能点

  • 动态更新 scale 值,限制缩放比例范围。
  • 调用 getOffsetCorrection 确保缩放以鼠标位置为中心。

7. 关闭预览

点击遮罩层时,调用 closePreview 将图片平滑恢复到原始位置,并移除遮罩层。

核心代码

function closePreview(mask) {
  const { offsetWidth, offsetHeight } = originalEl;
  const { top, left } = originalEl.getBoundingClientRect();

  applyStyles(cloneEl, {
    transform: "translate(0,0)",
    left: `${left}px`,
    top: `${top}px`,
    width: `${offsetWidth}px`,
    transition: `all ${config.transitionDuration}ms`,
  });

  setTimeout(() => {
    mask.remove();
    cloneEl.remove();
  }, config.transitionDuration);
}

功能点

  • 通过动画平滑恢复图片位置。
  • 清理 DOM 节点,释放内存。

8. 初始化调用入口

通过以下方法初始化图片预览功能:

window.previewImg = function (selector = ".image-container img") {
  initialize(selector);
};

使用示例

// 调用图片预览功能
previewImg(".image-container img");

总结

本文介绍了一种简单高效的图片预览功能,可轻松集成到各种项目中。希望本文对您有所帮助!