javascript基础之购物车主图放大镜功能

首先在淘宝上找一个宝贝链接,打开控制台,看一下淘宝上的放大镜功能的结构是怎样实现的

image.png

不难看出来,主图区域功能最外面一层是div用来存放主要功能区的,position: relative;,主图并没有定位,只是一个img标签,滑块区域和放大图区域都是相对于外侧父元素定位,附图利用background-position来改变位置,其次主图和放大图下载下来后,尺寸属性是一样的,都是750 * 1000,那么首先在html中搭建这样的一个结构。

html结构

在vscode中输入main>(div.product-img>img+div.zoom+div.tools)+div.product-info回车,则会生成上述的结构,手动添加一个图片链接,为了防止之后链接失效,

html <main> <div class="product-img"> <img src="" alt="商品主图"> <div class="zoom"></div> <div class="tools"></div> </div> <div class="product-info"></div> </main>

样式

根据结构,写less设置一下各个dom节点的样式

```less main{ display:flex; height: 450px; margin-right: 18px; width: 100%; .product-img { position: relative; height: 100%; width: 450px; background-color: #efefef; img { display:block; height: 100%; // 按照父元素尺寸等比缩放 width: calc((450 / 1000) * 750px); margin: auto; } .zoom { position: absolute; top: 0; right: -20px; transform: translateX(100%); background-image: url(../assets/image/product.png); width: 388px; height: 100%; // 固定图片值,可动态获取 background-size: 750px 1000px; border-radius: 10px; overflow: hidden; z-index: 2; } .tools { width: 128px; height: 128px; background: rgba(129, 167, 249, 0.485); position: absolute; left: 0; top: 0; z-index: 2; } } .product-info { flex: 4; background: #9f9f9f; }

} ```

加入样式的布局

image.png

放大逻辑

.tools滑块移动

分析一下滑块移动的范围,超过主图的范围禁止超越,超过主图外侧dom节点的位置滑块隐藏,前期为了方便观察,先不做隐藏功能,只做移动和范围限制。

这四条蓝色的线,就是滑块可移动的最大范围

```typescript class Vector2 { x: number; y: number; constructor(x = 0, y = 0) { this.x = x; this.y = y } // 相加 add(v2: Vector2) { return new Vector2(v2.x + this.x, v2.y + this.y) } // 相减 sub(v2: Vector2) { return new Vector2(this.x - v2.x, this.y - v2.y) } divided(n: number) { return new Vector2(this.x / n, this.y / n) } }

// 获取图片相关尺寸 const img = document.querySelector('img') const width = img?.offsetWidth const height = img?.offsetHeight const imgSize = new Vector2(width, height)

// 图片左上角距离父元素的位置 const imgLeft = img?.offsetLeft const imgTop = img?.offsetTop const LT = new Vector2(imgLeft, imgTop) // 图片右下角位置 const RB = LT.add(imgSize)

const imgParent = document.querySelector('.product-img') as any; const parentPos = new Vector2(imgParent.offsetLeft, imgParent.offsetTop)

// zoom图层信息 const zoom = document.querySelector('.zoom') as HTMLDivElement; const zoomSize = new Vector2(zoom.offsetWidth, zoom.offsetHeight)

// 移动模块相关参数 const tools = document.querySelector('.tools') as HTMLDivElement; const toolsLeft = tools.offsetLeft; const toolsTop = tools.offsetTop;

// 根据zoom图层跟大图尺寸的比例计算出tools的尺寸 // 犯懒了,750和1000这两个数值应该从图片上获取 const toolsWidth = zoomSize.x / 750 * imgSize.x const toolsHeight = zoomSize.y / 1000 * imgSize.y tools.style.width = toolsWidth + 'px' tools.style.height = toolsHeight + 'px' const toolsSize = new Vector2(toolsWidth, toolsHeight)

// 鼠标位置 const mouseMove = (e: any) => { // 获取当前鼠标位置 const mouse = new Vector2(e?.clientX, e?.clientY); // console.dir(mouse); // 鼠标当前位置-父元素距离页面位置-模块尺寸的一半 const toolsPosition = mouse.sub(parentPos).sub(toolsSize.divided(2)) tools.style.left = toolsPosition.x + 'px' tools.style.top = toolsPosition.y + 'px' }

if (imgParent) { imgParent.onmousemove = mouseMove }

```

以上为移动模块的功能,效果如下

关于Vector2类是为了方便各个坐标之间的计算,不使用也可以,只要能计算出来就行,

限制范围

新增一个限制方法,传入当前模块位置,进行限制后,返回可在位置的值

```typescript // 图片右下角限制 const RBRange = RB.sub(toolsSize) // 限制范围 const limitRange = (pos: Vector2): Vector2 => { let { x, y } = pos

// 先判断左上角
x = x >= LT.x ? x : LT.x
y = y >= LT.y ? y : LT.y

// 再判断右下角
x = x <= RBRange.x ? x : RBRange.x
y = y <= RBRange.y ? y : RBRange.y

return new Vector2(x, y)

} ```

在mousemove方法中使用这个限制方法

typescript ... const pos = limitRange(toolsPosition) tools.style.left = pos.x + 'px' tools.style.top = pos.y + 'px' ...

限制范围后的效果

放大zoom图

按照上图的比例计算公式,带入到getScale方法中,改变.zoom元素的backgroundPosition属性

```typescript const getScale = () => { // 改变左右位置 const left = tools.offsetLeft - (img?.offsetLeft || 0) const scaleX = left / imgSize.x const x = scaleX * zoomBackgroundImageWidth zoom.style.backgroundPositionX = -x + 'px'

// 改变上下位置
const top = tools.offsetTop - (img?.offsetTop || 0)
const scaleY = top / imgSize.y
const y = scaleY * zoomBackgroundImageHeight
zoom.style.backgroundPositionY = -y + 'px'

} ```

zoomBackgroundImageWidth 这个尺寸是大图的原本的尺寸,前面写的固定值,按理说这个值应该动态获取。

细节调整

接下来剩的工作就相对简单一点,根据不同时机,将元素显示隐藏即可

2023-06-09 10.06.51.gif

jcode

历史文章

# 写一个高德地图巡航功能的小DEMO

# Javascript基础之鼠标拖拉拽

# threejs 打造 world.ipanda.com 同款3D首页

# three.js——镜头跟踪

# threejs 笔记 03 —— 轨道控制器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙华鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值