JS 打造「放大镜 + 缩略图」一体组件

电商详情页的经典三件套:缩略图列表 + 中等图展示 + 局部放大图。本文js原生代码实现一条无依赖、可复用、可扩展的放大镜链路,涵盖事件委托、边界计算、背景定位三大核心技能。

效果预览

一、HTML 骨架

html 复制代码
<div class="container">
  <!-- 中等图 -->
  <div class="left-img">
    <div class="mask"></div>
  </div>
  <!-- 放大图 -->
  <div class="right-img"></div>
  <!-- 缩略图列表 -->
  <ul class="img-list"></ul>
</div>
  • left-img:中等图,承担点击切换与鼠标探测双重职责
  • mask:绝对定位遮罩,用于局部高亮与边界计算
  • right-img:放大图,背景图定位实现局部放大效果

二、数据约定

js 复制代码
var imgs = {
  small: ['imgA_1.jpg', 'imgB_1.jpg', 'imgC_1.jpg'],
  middle: ['imgA_2.jpg', 'imgB_2.jpg', 'imgC_2.jpg'],
  large: ['imgA_3.jpg', 'imgB_3.jpg', 'imgC_3.jpg']
}
  • 三张图按索引一一对应,切换时只需同步 backgroundImage
  • 缩略图定宽定高,中等图与放大图定宽不定高,保持比例

三、JS链式事件三步走

1.初始化:渲染缩略图 + 默认激活

js 复制代码
function initPage() {
  let html = ''
  for (let i = 0; i < imgs.small.length; i++) {
    html += `<li style="background-image:url(./images/${imgs.small[i]});"></li>`
  }
  $('.img-list').innerHTML = html
  $('.img-list li').style.border = '2px solid #000'   // 默认选中第一张
}

2.点击缩略图:同步切换中等图与大图

js 复制代码
$('.img-list').onclick = function (e) {
  if (e.target.tagName !== 'LI') return
  // 让所有 LI 失活
  $$('li').forEach(li => li.style.border = 'none')
  // 让当前 LI 激活
  e.target.style.border = '2px solid #000'

  const index = [].indexOf.call(this.children, e.target)
  $('.left-img').style.backgroundImage = `url(./images/${imgs.middle[index]})`
  $('.right-img').style.backgroundImage = `url(./images/${imgs.large[index]})`
}

使用事件委托,缩略图数量随意增减,无需重新绑定。

3.鼠标移动:遮罩层跟随 + 大图定位

js 复制代码
$('.left-img').onmousemove = function (e) {
  const mask = $('.mask')
  const large = $('.right-img')
  mask.style.opacity = 1
  large.style.opacity = 1

  // 计算遮罩层中心坐标
  let left = e.clientX - this.offsetLeft - mask.offsetWidth / 2
  let top = e.clientY - this.offsetTop - mask.offsetHeight / 2

  // 边界条件:不让遮罩跑出中等图
  left = Math.max(0, Math.min(left, this.offsetWidth - mask.offsetWidth))
  top = Math.max(0, Math.min(top, this.offsetHeight - mask.offsetHeight))

  mask.style.left = left + 'px'
  mask.style.top = top + 'px'

  // 大图反向移动,实现局部放大
  large.style.backgroundPositionX = -left + 'px'
  large.style.backgroundPositionY = -top + 'px'
}

边界计算拆解

  • left ≤ 0 时强制归零
  • left ≥ (中等图宽 - 遮罩宽) 时强制贴边
  • 同理处理 top 高度方向

背景定位技巧

遮罩向右移动 10px,大图背景向左移动 10px,形成「窗口」效果;Y 轴同理。


四、鼠标离开:自动隐藏

js 复制代码
$('.left-img').onmouseleave = function () {
  $('.mask').style.opacity = 0
  $('.right-img').style.opacity = 0
}

只用 opacity 控制显隐,避免 display: none 触发重排;背景图已预加载,无闪烁。

性能 & 扩展

  • 零依赖:原生 DOM API,gzip < 1 KB
  • 零重排:仅用 opacitybackground-position,不改动布局
  • 可异步:把 initPage 换成 fetch 即可接入后端图片列表
  • 可响应:把 offsetWidth 换成 getBoundingClientRect 即可适配缩放
相关推荐
陈随易2 小时前
适合中国宝宝的AI编程神器,文心快码
前端·后端·node.js
知识分享小能手2 小时前
React学习教程,从入门到精通,React AJAX 语法知识点与案例详解(18)
前端·javascript·vue.js·学习·react.js·ajax·vue3
UrbanJazzerati2 小时前
掌握 DOM 的基础属性与方法:从操作元素到构建动态效果
前端·面试
hashiqimiya3 小时前
html实现右上角有个图标,鼠标移动到该位置出现手型,点击会弹出登录窗口。
前端·html
古夕3 小时前
前端文件下载的三种方式:a标签、Blob、ArrayBuffer
前端·javascript·vue.js
纯真时光3 小时前
Vue3中pinia状态管理库的使用(Composition API 风格)
前端
李李记3 小时前
Node.js 打包踩坑?NCC+PKG 从单文件到多平台可执行文件,解决 axios 缺失等 80% 问题
javascript
万少3 小时前
可可图片编辑 HarmonyOS(5)滤镜效果
前端
2301_781668613 小时前
微服务面试篇
微服务·面试·架构