LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

使用 HTML + JavaScript 实现商品图片放大镜(附完整代码)

admin
2025年12月14日 17:6 本文热度 763
在现代电商网站中,商品图片的细节展示对于提升用户体验和促进购买决策至关重要。放大镜效果作为一种经典的商品图片展示方式,能够让用户清晰地查看商品的每一个细节。本文将详细介绍如何使用 HTML、CSS 和 JavaScript 实现一个功能完整的商品图片放大镜效果。

效果演示

该放大镜功能主要包括以下几个交互体验:

  • 左侧缩略图列表,支持点击切换主图

  • 主图区域鼠标悬停时显示放大镜效果

  • 右侧同步显示放大的局部图像

  • 支持左右导航按钮切换图片

  • 缩略图悬停时自动预览对应图片

用户可以通过点击缩略图或者使用导航按钮来浏览不同角度的商品图片,当鼠标移动到主图上时,会显示出一个放大镜区域,并在右侧展示对应的高清放大图像。

页面结构

整个页面采用了经典的两栏布局设计,左侧为缩略图区域,右侧为主图及放大预览区域。

缩略图区域

缩略图区域位于页面左侧,垂直排列多个小尺寸的商品图片缩略图。每个缩略图都带有边框高亮效果,当前选中的缩略图会有橙色边框标识。
<div class="thumbnails" id="thumbnailsContainer"></div>

主图与放大镜区域

主图区域占据页面右侧大部分空间,包含实际展示的商品大图、放大镜遮罩层以及放大预览窗口。
<div class="product-viewer">  <div class="main-image-container" id="mainContainer">    <img class="main-image" id="mainImage" src="" alt="Product Image">    <div class="magnifier-lens" id="magnifierLens"></div>    <button class="nav-btn prev-btn" id="prevBtn"></button>    <button class="nav-btn next-btn" id="nextBtn"></button>  </div>  <div class="zoom-preview" id="zoomPreview"></div></div>

核心功能实现

渲染缩略图

renderThumbnails() 函数负责动态生成并显示商品图片的缩略图列表。
function renderThumbnails() {  thumbnailsContainer.innerHTML = '';  imageData.forEach(function(image, index) {    var thumbnail = document.createElement('div');    thumbnail.className = 'thumbnail ' + (index === currentState.currentIndex ? 'active' : '');    thumbnail.dataset.index = index;    thumbnail.innerHTML = '<img src="' + image.small + '" alt="Thumbnail ' + index + '">';    thumbnailsContainer.appendChild(thumbnail);  });}

更新主图

updateMainImage() 函数负责更新主图显示区域和放大预览区域的图片内容。
function updateMainImage() {  var currentImage = imageData[currentState.currentIndex];  mainImage.src = currentImage.small;  zoomPreview.style.backgroundImage = 'url(' + currentImage.large + ')';
  // 等待图片加载完成后设置背景尺寸  mainImage.onload = function() {    setBackgroundSize();  };
  // 如果图片已缓存,直接设置背景尺寸  if (mainImage.complete) {    setBackgroundSize();  }}

放大镜交互逻辑

放大镜的核心在于精确计算放大镜的位置和大小,并同步控制预览区域的背景位置。当鼠标进入主图容器时触发 showMagnifier() 显示放大镜和预览窗口;离开时通过 hideMagnifier() 隐藏它们。在鼠标移动过程中,moveMagnifier() 函数实时计算并更新放大镜位置及其在预览区的对应显示区域。

function moveMagnifier(e) {  var containerRect = mainContainer.getBoundingClientRect();  var x = e.clientX - containerRect.left;  var y = e.clientY - containerRect.top;
  // 计算放大镜尺寸(使用整数避免小数问题)  var lensWidth = Math.floor(mainContainer.offsetWidth / currentState.zoomFactor);  var lensHeight = Math.floor(mainContainer.offsetHeight / currentState.zoomFactor);
  // 计算放大镜位置(先计算中心点,再确定左上角位置)  var lensX = Math.round(x - lensWidth / 2);  var lensY = Math.round(y - lensHeight / 2);
  // 严格的边界限制(确保右边界和下边界也不会超出)  lensX = Math.max(0Math.min(lensX, containerRect.width - lensWidth));  lensY = Math.max(0Math.min(lensY, containerRect.height - lensHeight));
  // 设置放大镜位置和尺寸  magnifierLens.style.left = lensX + 'px';  magnifierLens.style.top = lensY + 'px';  magnifierLens.style.width = lensWidth + 'px';  magnifierLens.style.height = lensHeight + 'px';
  // 计算预览区域背景位置  var percentX = x / containerRect.width;  var percentY = y / containerRect.height;
  // 获取背景总尺寸  var bgWidth = mainContainer.offsetWidth * currentState.zoomFactor;  var bgHeight = mainContainer.offsetHeight * currentState.zoomFactor;
  // 计算预览区域可视窗口尺寸  var previewWidth = zoomPreview.offsetWidth;  var previewHeight = zoomPreview.offsetHeight;
  // 计算背景位置,使鼠标位置居中显示  var previewBgX = -(percentX * bgWidth - previewWidth / 2);  var previewBgY = -(percentY * bgHeight - previewHeight / 2);
  // 限制背景位置,避免显示空白区域  if (bgWidth <= previewWidth) {    previewBgX = (previewWidth - bgWidth) / 2;  } else {    previewBgX = Math.max(previewWidth - bgWidth, Math.min(0, previewBgX));  }
  if (bgHeight <= previewHeight) {    previewBgY = (previewHeight - bgHeight) / 2;  } else {    previewBgY = Math.max(previewHeight - bgHeight, Math.min(0, previewBgY));  }
  zoomPreview.style.backgroundPosition = previewBgX + 'px ' + previewBgY + 'px';}

完整代码

git地址:https://gitee.com/ironpro/hjdemo/blob/master/magnifier/index.html
<!DOCTYPE html><html lang="zh-CN"><head>  <meta charset="UTF-8">  <title>商品图片放大镜</title>  <style>    * {      margin0;      padding0;      box-sizing: border-box;    }
    body {      background-color#f5f5f5;      padding30px;    }    .container {      max-width1200px;      margin0 auto;      display: flex;      gap30px;    }    .thumbnails {      width68px;      display: flex;      flex-direction: column;      gap10px;    }
    .thumbnail {      width100%;      height68px;      border2px solid transparent;      cursor: pointer;      overflow: hidden;      transition: border-color 0.3s;    }
    .thumbnail.active {      border-color#ff6600;    }
    .thumbnail img {      width100%;      height100%;      object-fit: cover;    }
    /* 主图区域 */    .product-viewer {      flex1;      position: relative;      display: flex;      gap30px;    }
    .main-image-container {      position: relative;      width500px;      height500px;      background: white;      overflow: hidden;    }
    .main-image {      width100%;      height100%;      object-fit: contain;    }
    .magnifier-lens {        position: absolute;        box-shadow0 0 5px rgba(0000.5);        cursor: none;        display: none;        pointer-events: none;        background-colorrgba(2552552550.3);    }
    .zoom-preview {      width500px;      height500px;      border1px solid #ddd;      background-color: white;      background-repeat: no-repeat;      display: none;      overflow: hidden;    }
    /* 控制按钮 */    .nav-btn {      position: absolute;      top50%;      transformtranslateY(-50%);      backgroundrgba(0000.5);      color: white;      border: none;      width40px;      height40px;      font-size18px;      cursor: pointer;      z-index10;    }
    .prev-btn {      left10px;    }
    .next-btn {      right10px;    }
    .nav-btn:hover {      backgroundrgba(0000.8);    }  </style></head><body>  <div class="container">    <!-- 缩略图列表 -->    <div class="thumbnails" id="thumbnailsContainer"></div>
    <!-- 主图和放大镜区域 -->    <div class="product-viewer">      <div class="main-image-container" id="mainContainer">        <img class="main-image" id="mainImage" src="" alt="Product Image">        <div class="magnifier-lens" id="magnifierLens"></div>        <button class="nav-btn prev-btn" id="prevBtn"></button>        <button class="nav-btn next-btn" id="nextBtn"></button>      </div>      <div class="zoom-preview" id="zoomPreview"></div>    </div>  </div>  <script>    // 数据和配置    var imageData = [      { small'https://picsum.photos/seed/a/450/450'large'https://picsum.photos/seed/a/1125/1125' },      { small'https://picsum.photos/seed/b/450/450'large'https://picsum.photos/seed/b/1125/1125' },      { small'https://picsum.photos/seed/c/450/450'large'https://picsum.photos/seed/c/1125/1125' },      { small'https://picsum.photos/seed/d/450/450'large'https://picsum.photos/seed/d/1125/1125' },      { small'https://picsum.photos/seed/e/450/450'large'https://picsum.photos/seed/e/1125/1125' },      { small'https://picsum.photos/seed/f/450/450'large'https://picsum.photos/seed/f/1125/1125' }    ];    // DOM 元素引用    var thumbnailsContainer = document.getElementById('thumbnailsContainer');    var mainContainer = document.getElementById('mainContainer');    var mainImage = document.getElementById('mainImage');    var magnifierLens = document.getElementById('magnifierLens');    var zoomPreview = document.getElementById('zoomPreview');    var prevBtn = document.getElementById('prevBtn');    var nextBtn = document.getElementById('nextBtn');
    var currentState = {      currentIndex0,      zoomFactor2.5    };    // 缩略图悬停事件    thumbnailsContainer.addEventListener('mouseover'function(e) {      var thumbnail = e.target.closest('.thumbnail');      if (thumbnail && !thumbnail.classList.contains('active')) {        var index = parseInt(thumbnail.dataset.index);        switchImage(index);      }    });
    // 主图鼠标事件    mainContainer.addEventListener('mouseenter', showMagnifier);    mainContainer.addEventListener('mouseleave', hideMagnifier);    mainContainer.addEventListener('mousemove', moveMagnifier);
    // 导航按钮事件    prevBtn.addEventListener('click', previousImage);    nextBtn.addEventListener('click', nextImage);
    // 渲染初始状态    function render() {      renderThumbnails();      updateMainImage();    }
    // 渲染缩略图    function renderThumbnails() {      thumbnailsContainer.innerHTML = '';      imageData.forEach(function(image, index) {        var thumbnail = document.createElement('div');        thumbnail.className = 'thumbnail ' + (index === currentState.currentIndex ? 'active' : '');        thumbnail.dataset.index = index;        thumbnail.innerHTML = '<img src="' + image.small + '" alt="Thumbnail ' + index + '">';        thumbnailsContainer.appendChild(thumbnail);      });    }
    // 更新主图    function updateMainImage() {      var currentImage = imageData[currentState.currentIndex];      mainImage.src = currentImage.small;      zoomPreview.style.backgroundImage = 'url(' + currentImage.large + ')';
      // 等待图片加载完成后设置背景尺寸      mainImage.onload = function() {        setBackgroundSize();      };
      // 如果图片已缓存,直接设置背景尺寸      if (mainImage.complete) {        setBackgroundSize();      }    }
    // 设置背景大小    function setBackgroundSize() {      var containerWidth = mainContainer.offsetWidth;      var containerHeight = mainContainer.offsetHeight;
      // 直接计算放大后的绝对尺寸      var bgWidth = containerWidth * currentState.zoomFactor;      var bgHeight = containerHeight * currentState.zoomFactor;
      // 只设置 zoomPreview 的背景尺寸      zoomPreview.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px';    }
    // 切换图片    function switchImage(index) {      currentState.currentIndex = index;      render();    }
    // 上一张图片    function previousImage() {      currentState.currentIndex = (currentState.currentIndex - 1 + imageData.length) % imageData.length;      render();    }
    // 下一张图片    function nextImage() {      currentState.currentIndex = (currentState.currentIndex + 1) % imageData.length;      render();    }
    // 显示放大镜    function showMagnifier() {      magnifierLens.style.display = 'block';      zoomPreview.style.display = 'block';    }
    // 隐藏放大镜    function hideMagnifier() {      magnifierLens.style.display = 'none';      zoomPreview.style.display = 'none';    }
    // 移动放大镜    function moveMagnifier(e) {      var containerRect = mainContainer.getBoundingClientRect();      var x = e.clientX - containerRect.left;      var y = e.clientY - containerRect.top;
      // 计算放大镜尺寸(使用整数避免小数问题)      var lensWidth = Math.floor(mainContainer.offsetWidth / currentState.zoomFactor);      var lensHeight = Math.floor(mainContainer.offsetHeight / currentState.zoomFactor);
      // 计算放大镜位置(先计算中心点,再确定左上角位置)      var lensX = Math.round(x - lensWidth / 2);      var lensY = Math.round(y - lensHeight / 2);
      // 严格的边界限制(确保右边界和下边界也不会超出)      lensX = Math.max(0Math.min(lensX, containerRect.width - lensWidth));      lensY = Math.max(0Math.min(lensY, containerRect.height - lensHeight));
      // 设置放大镜位置和尺寸      magnifierLens.style.left = lensX + 'px';      magnifierLens.style.top = lensY + 'px';      magnifierLens.style.width = lensWidth + 'px';      magnifierLens.style.height = lensHeight + 'px';
      // 计算预览区域背景位置      var percentX = x / containerRect.width;      var percentY = y / containerRect.height;
      // 获取背景总尺寸      var bgWidth = mainContainer.offsetWidth * currentState.zoomFactor;      var bgHeight = mainContainer.offsetHeight * currentState.zoomFactor;
      // 计算预览区域可视窗口尺寸      var previewWidth = zoomPreview.offsetWidth;      var previewHeight = zoomPreview.offsetHeight;
      // 计算背景位置,使鼠标位置居中显示      var previewBgX = -(percentX * bgWidth - previewWidth / 2);      var previewBgY = -(percentY * bgHeight - previewHeight / 2);
      // 限制背景位置,避免显示空白区域      if (bgWidth <= previewWidth) {        previewBgX = (previewWidth - bgWidth) / 2;      } else {        previewBgX = Math.max(previewWidth - bgWidth, Math.min(0, previewBgX));      }
      if (bgHeight <= previewHeight) {        previewBgY = (previewHeight - bgHeight) / 2;      } else {        previewBgY = Math.max(previewHeight - bgHeight, Math.min(0, previewBgY));      }
      zoomPreview.style.backgroundPosition = previewBgX + 'px ' + previewBgY + 'px';    }    render();  </script></body></html>


阅读原文:原文链接


该文章在 2025/12/15 9:03:57 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved