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
  • 零重排:仅用 opacity 与 background-position,不改动布局
  • 可异步:把 initPage 换成 fetch 即可接入后端图片列表
  • 可响应:把 offsetWidth 换成 getBoundingClientRect 即可适配缩放
相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万5 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
晨米酱5 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄5 天前
JavaScript 隐式全局变量解析
javascript
彧azz5 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端