图片切换模块及放大镜效果
分析:
- 鼠标经过对应小盒子,左侧中等盒子显示对应中等图片
- 鼠标经过中盒子,右侧会显示放大镜效果的大盒子
- 黑色遮罩盒子跟着鼠标来移动
- 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置
思路分析:①:鼠标经过小盒子,左侧中等盒子显示对应中等图片
获取对应的元素
采取事件委托的形式,监听鼠标经过小盒子里面的图片, 注意此时需要使用
mouseover
事件,因为需要事件冒泡触发small让鼠标经过小图片的爸爸li盒子,添加类,其余的li移除类(注意先移除,后添加)
鼠标经过小图片,可以拿到小图片的src, 可以做两件事
让中等盒子的图片换成这个 这个小图片的src
让大盒子的背景图片,也换成这个小图片的 src (稍后做)
②: 鼠标经过中等盒子,右侧大盒子显示
用到鼠标经过和离开,鼠标经过中盒子,大盒子 利用 display 来显示和隐藏
鼠标离开不会立马消失,而是有200ms的延时,用户体验更好,所以尽量使用定时器做个延时 setTimeout
显示和隐藏也尽量定义一个函数,因为鼠标经过离开中等盒子,会显示隐藏,同时,鼠标经过大盒子,也会显示和隐藏
给大盒子里面的背景图片一个默认的第一张图片
③: 黑色遮罩盒子跟着鼠标来移动
先做鼠标经过 中等盒子,显示隐藏 黑色遮罩 的盒子
让黑色遮罩跟着鼠标来走, 需要用到鼠标移动事件 mousemove
让黑色盒子的移动的核心思想:不断把鼠标在中等盒子内的坐标给黑色遮罩层 let top 值,这样遮罩层就可以跟着移动了
需求
我们要的是 鼠标在 中等盒子内的坐标, 没有办法直接得到
得到1: 鼠标在页面中的坐标
得到2: 中等盒子在页面中的坐标
算法
得到鼠标在页面中的坐标 利用事件对象的 pageX
得到middle中等盒子在页面中的坐标 middle.getBoundingClientRect()
鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标
黑色遮罩层不断得到 鼠标在middle 盒子中的坐标 就可以移动起来了
注意 y坐标特殊,需要减去 页面被卷去的头部
为什么不用 box.offsetLet 和 box.offsetTop 因为这俩属性跟带有定位的父级有关系,很容被父级影响,而getBoundingClientRect() 不受定位的父元素的影响
限定遮罩的盒子只能在middle 内部移动,需要添加判断
限定水平方向 大于等于0 并且小于等于 400
限定垂直方向 大于等于0 并且小于等于 400
遮罩盒子移动的坐标:
声明一个 mx 作为移动的距离
水平坐标 x 如果 小于等于100 ,则移动的距离 mx 就是 0 不应该移动
水平坐标 如果 大于等于100 并且小于300,移动的距离就是 mx - 100 (100是遮罩盒子自身宽度的一半)
水平坐标 如果 大于等于300,移动的距离就是 mx 就是200 不应该在移动了
其实我们发现水平移动, 就在 100 ~ 200 之间移动的
垂直同理
javascriptlet mx = 0, my = 0; if (x <= 100) mx = 0 if (x > 100 && x < 300) mx = x - 100 if (x >= 300) mx = 200 if (y <= 100) my = 0 if (y > 100 && y < 300) my = y - 100 if (y >= 300) my = 200
大盒子图片移动的计算方法:
中等盒子是 400px 大盒子 是 800px 的图片
中等盒子移动1px, 大盒子就应该移动2px, 只不过是负值
javascriptlarge.style.backgroundPositionX = - 2 * mx + 'px' large.style.backgroundPositionY = - 2 * my + 'px'
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>小兔鲜儿 - 新鲜 惠民 快捷!</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<!-- <link rel="stylesheet" href="//at.alicdn.com/t/font_1939705_bgtmkonu28.css"> -->
<link rel="stylesheet" href="./css/common.css">
<link rel="stylesheet" href="./css/product.css">
</head>
<body>
<!-- 项部导航 -->
<div class="xtx_topnav">
<div class="wrapper">
<!-- 顶部导航 -->
<ul class="xtx_navs">
<li>
<a href="javascript:;">请先登录</a>
</li>
<li>
<a href="javascript:;">免费注册</a>
</li>
<li>
<a href=".javascript:;">我的订单</a>
</li>
<li>
<a href="javascript:;">会员中心</a>
</li>
<li>
<a href="javascript:;">帮助中心</a>
</li>
<li>
<a href="javascript:;">在线客服</a>
</li>
<li>
<a href="javascript:;">
<i class="mobile sprites"></i>
手机版
</a>
</li>
</ul>
</div>
</div>
<!-- 头部 -->
<div class="xtx_header">
<div class="wrapper">
<!-- 网站Logo -->
<h1 class="xtx_logo"><a href="/">小兔鲜儿</a></h1>
<!-- 主导航 -->
<div class="xtx_navs">
<ul class="clearfix">
<li>
<a href="javascript:;">首页</a>
</li>
<li>
<a href="javascript:;">生鲜</a>
</li>
<li>
<a href="javascript:;">美食</a>
</li>
<li>
<a href="javascript:;">餐厨</a>
</li>
<li>
<a href="javascript:;">电器</a>
</li>
<li>
<a href="javascript:;">居家</a>
</li>
<li>
<a href="javascript:;">洗护</a>
</li>
<li>
<a href="javascript:;">孕婴</a>
</li>
<li>
<a href="javascript:;">服装</a>
</li>
</ul>
</div>
<!-- 站内搜索 -->
<div class="xtx_search clearfix">
<!-- 购物车 -->
<a href="javascript:;" class="xtx_search_cart sprites">
<i>2</i>
</a>
<!-- 搜索框 -->
<div class="xtx_search_wrapper">
<input type="text" placeholder="搜一搜" onclick="location.href='./search.html'">
</div>
</div>
</div>
</div>
<div class="xtx-wrapper">
<div class="container">
<!-- 面包屑 -->
<div class="xtx-bread">
<a href="javascript:;"> 首页 > </a>
<a href="javascript:;"> 电子产品 > </a>
<a href="javascript:;"> 电视 > </a>
<span>小米电视4A 32英寸</span>
</div>
<!-- 商品信息 -->
<div class="xtx-product-info">
<div class="left">
<div class="pictrue">
<div class="middle">
<img src="./images/1.jpg" alt="">
<div class="layer"></div>
</div>
<div class="small">
<ul>
<li class="active"><img src="./images/1.jpg" alt=""></li>
<li><img src="./images/2.jpg" alt=""></li>
<li><img src="./images/3.jpg" alt=""></li>
<li><img src="./images/4.jpg" alt=""></li>
<li><img src="./images/5.jpg" alt=""></li>
</ul>
</div>
<div class="large"></div>
</div>
<div class="other">
<ul>
<li>
<p>销量人气</p>
<p>1999+</p>
<p>销量人气</p>
</li>
<li>
<p>商品评价</p>
<p>999+</p>
<p>查看评价</p>
</li>
<li>
<p>收藏人气</p>
<p>299+</p>
<p><a href="javascript:;">收藏商品</a></p>
</li>
<li>
<p>品牌信息</p>
<p>小米</p>
<p><a href="javascript:;">品牌主页</a></p>
</li>
</ul>
</div>
</div>
<div class="right">
<h3 class="name">小米电视4A 32英寸</h3>
<p class="desc">全面屏设计 / 高清分辨率 / 海量内容 / 1G+4G大内存 / 多核处理器</p>
<p class="price"><span class="now">¥1899</span><span class="old">¥2999</span></p>
<div class="address">
<div class="item">
<div class="dt">促销</div>
<div class="dd">12月好物放送,App领券购买直降120元</div>
</div>
<div class="item">
<div class="dt">配送</div>
<div class="dd">至
<div class="box">
<span>陕西 西安 <i></i></span>
</div>
</div>
</div>
<div class="item">
<div class="dt">服务</div>
<div class="dd">
<span class="fw">无忧退货</span>
<span class="fw">快速退款</span>
<span class="fw">免费包邮</span>
<a href="#" class="lj">了解详情</a>
</div>
</div>
</div>
<div class="attrs">
<div class="item">
<div class="dt">颜色</div>
<div class="dd">
<img src="./uploads/img/cate-06.png" alt="">
<img src="./uploads/img/cate-07.png" alt="">
</div>
</div>
<div class="item">
<div class="dt">颜色</div>
<div class="dd">
<span class="size">22英寸</span>
<span class="size">42英寸</span>
<span class="size">52英寸</span>
<span class="size">62英寸</span>
</div>
</div>
<div class="item">
<div class="dt">数量</div>
<div class="dd">
<div class="num">
<a href="javascript:;">-</a>
<input type="text" value="1">
<a href="javascript:;">+</a>
</div>
</div>
</div>
<div class="item">
<a class="buy" href="javascript:;">立即购买</a>
</div>
</div>
</div>
</div>
<!-- 同类产品推荐 -->
<div class="xtx-relevant-product">
<h3>同类产品推荐</h3>
<ul>
<li>
<a href="#">
<img src="./uploads/history_goods_1.jpg" alt="">
<p class="name">USB Type C数据线</p>
<p class="desc">快速充电,稳定传输</p>
<p class="price">¥39</p>
</a>
</li>
<li>
<a href="#">
<img src="./uploads/history_goods_2.jpg" alt="">
<p class="name">红米Note 5A 高配版</p>
<p class="desc">1600万像素柔光自拍</p>
<p class="price">¥1899</p>
</a>
</li>
<li>
<a href="#">
<img src="./uploads/history_goods_3.jpg" alt="">
<p class="name">VGA网口多功能转接器</p>
<p class="desc">小巧便携,节省桌面空间</p>
<p class="price">¥19</p>
</a>
</li>
<li>
<a href="#">
<img src="./uploads/history_goods_4.jpg" alt="">
<p class="name">笔记本Pro 15.6"</p>
<p class="desc">全金属强化机身搭配独显</p>
<p class="price">¥4899</p>
</a>
</li>
</ul>
<a href="javascript:;" class="prev"><span class="iconfont icon-angle-left"></span></a>
<a href="javascript:;" class="next"><span class="iconfont icon-angle-right"></span></a>
</div>
<!-- 商品详情 -->
<div class="xtx-product-detail">
<div class="main">
<div class="cont">
<div class="tab-head">
<a href="javascript:;">商品详情</a>
<a href="javascript:;">商品评价<span>(998+)</span></a>
</div>
<div class="tab-pane">
<!-- 静态属性 -->
<div class="attrs">
<div class="item"><span>商品名称:</span><span>小米L32M5-AZ </span></div>
<div class="item"><span>商品编号:</span><span>4620979 </span></div>
<div class="item"><span>商品毛重:</span><span>8.0kg </span></div>
<div class="item"><span>商品产地:</span><span>中国大陆 </span></div>
<div class="item"><span>屏幕尺寸:</span><span>32英寸及以下 </span></div>
<div class="item"><span>能效等级:</span><span>三级能效 </span></div>
<div class="item"><span>电视类型:</span><span>人工智能 </span></div>
<div class="item"><span>选购指数:</span><span>6.9-6.0 </span></div>
<div class="item"><span>观看距离:</span><span>2m以下(≤32英寸)</span></div>
</div>
<!-- 详情内容 -->
<div class="detail">
<img src="https://yanxuan-item.nosdn.127.net/39d7f2407c90d0442566a719146ee9c1.jpg" alt=""
data-v-2c43c764=""><img src="https://yanxuan-item.nosdn.127.net/7dfee58e7c6b3996badf368610ed62b1.jpg"
alt="" data-v-2c43c764=""><img
src="https://yanxuan-item.nosdn.127.net/d1acff1a29bddd21c2ad337d892a9f7c.jpg" alt=""
data-v-2c43c764=""><img src="https://yanxuan-item.nosdn.127.net/ac722b04b2014ac337d8db695ee46f0c.jpg"
alt="" data-v-2c43c764=""><img
src="https://yanxuan-item.nosdn.127.net/c63e36faa0848ee37c825897f5cec179.jpg" alt=""
data-v-2c43c764=""><img src="https://yanxuan-item.nosdn.127.net/e0f13dbf14c8a2f07e86bf3df3ca002b.jpg"
alt="" data-v-2c43c764="">
</div>
</div>
<div class="tab-pane" style="display: none;">评价</div>
</div>
<!-- 注意事项 -->
<div class="warn">
<h3>注意事项</h3>
<p class="tit">• 购买运费如何收取? </p>
<p>单笔订单金额(不含运费)满88元免邮费;不满88元,每单收取10元运费。(港澳台地区需满500元免邮费;不满500元,每单收取30元运费) </p>
<br>
<br>
<p class="tit">• 使用什么快递发货? </p>
<p>默认使用顺丰快递发货(个别商品使用其他快递) </p>
<p>配送范围覆盖全国大部分地区(港澳台地区除外)。 </p>
<br>
<br>
<p class="tit">• 如何申请退货? </p>
<p>1.自收到商品之日起30日内,顾客可申请无忧退货,退款将原路返还,不同的银行处理时间不同,预计1-5个工作日到账; </p>
<p>2.内裤和食品等特殊商品无质量问题不支持退货; </p>
<p>3.退货流程: 确认收货-申请退货-客服审核通过-用户寄回商品-仓库签收验货-退款审核-退款完成; </p>
<p>4.因小兔鲜儿产生的退货,如质量问题,退货邮费由小兔鲜儿承担,退款完成后会以现金券的形式报销。因客户个人原因产生的退货,购买和寄回运费由客户个人承担。</p>
</div>
</div>
<div class="aside">
<div class="tit">24小时热销榜</div>
<div class="product">
<img src="./uploads/fresh_goods_3.jpg" alt="">
<p class="name">USB Type C数据线</p>
<p class="desc">快速充电,稳定传输</p>
<p class="price">¥29</p>
</div>
<div class="product">
<img src="./uploads/fresh_goods_3.jpg" alt="">
<p class="name">USB Type C数据线</p>
<p class="desc">快速充电,稳定传输</p>
<p class="price">¥29</p>
</div>
<div class="product">
<img src="./uploads/fresh_goods_3.jpg" alt="">
<p class="name">USB Type C数据线</p>
<p class="desc">快速充电,稳定传输</p>
<p class="price">¥29</p>
</div>
<div class="tit">专题推荐</div>
<div class="special">
<img src="./uploads/discuss_goods_1.jpg" alt="">
<p class="name">一往无前,诞生于崛起</p>
</div>
<div class="special">
<img src="./uploads/discuss_goods_1.jpg" alt="">
<p class="name">一往无前,诞生于崛起</p>
</div>
<div class="special">
<img src="./uploads/discuss_goods_1.jpg" alt="">
<p class="name">一往无前,诞生于崛起</p>
</div>
</div>
</div>
</div>
</div>
<!-- 公共底部 -->
<div class="xtx_footer clearfix">
<div class="wrapper">
<!-- 联系我们 -->
<div class="contact clearfix">
<dl>
<dt>客户服务</dt>
<dd class="chat">在线客服</dd>
<dd class="feedback">问题反馈</dd>
</dl>
<dl>
<dt>关注我们</dt>
<dd class="weixin">公众号</dd>
<dd class="weibo">微博</dd>
</dl>
<dl>
<dt>下载APP</dt>
<dd class="qrcode">
<img src="./uploads/qrcode.jpg">
</dd>
<dd class="download">
<span>扫描二维码</span>
<span>立马下载APP</span>
<a href="javascript:;">下载页面</a>
</dd>
</dl>
<dl>
<dt>服务热线</dt>
<dd class="hotline">
400-0000-000
<small>周一至周日 8:00-18:00</small>
</dd>
</dl>
</div>
</div>
<!-- 其它 -->
<div class="extra">
<div class="wrapper">
<!-- 口号 -->
<div class="slogan">
<a href="javascript:;" class="price">价格亲民</a>
<a href="javascript:;" class="express">物流快捷</a>
<a href="javascript:;" class="quality">品质新鲜</a>
</div>
<!-- 版权信息 -->
<div class="copyright">
<p>
<a href="javascript:;">关于我们</a>
<a href="javascript:;">帮助中心</a>
<a href="javascript:;">售后服务</a>
<a href="javascript:;">配送与验收</a>
<a href="javascript:;">商务合作</a>
<a href="javascript:;">搜索推荐</a>
<a href="javascript:;">友情链接</a>
</p>
<p>CopyRight © 小兔鲜儿</p>
</div>
</div>
</div>
</div>
<script>
// 1. 获取三个盒子
// 2. 小盒子 图片切换效果
const small = document.querySelector('.small')
// 中盒子
const middle = document.querySelector('.middle')
// 大盒子
const large = document.querySelector('.large')
// 2. 事件委托
small.addEventListener('mouseover', function (e) {
if (e.target.tagName === 'IMG') {
// console.log(111)
// 排他 干掉以前的 active li 上面
this.querySelector('.active').classList.remove('active')
// 当前元素的爸爸添加 active
e.target.parentNode.classList.add('active')
// 拿到当前小图片的 src
// console.log(e.target.src)
// 让中等盒子里面的图片,src 更换为 小图片src
middle.querySelector('img').src = e.target.src
// 大盒子更换背景图片
large.style.backgroundImage = `url(${e.target.src})`
}
})
// 3. 鼠标经过中等盒子, 显示隐藏 大盒子
middle.addEventListener('mouseenter', show)
middle.addEventListener('mouseleave', hide)
let timeId = null
// 显示函数 显示大盒子
function show() {
// 先清除定时器
clearTimeout(timeId)
large.style.display = 'block'
}
// 隐藏函数 隐藏大盒子
function hide() {
timeId = setTimeout(function () {
large.style.display = 'none'
}, 200)
}
// 4. 鼠标经过大盒子, 显示隐藏 大盒子
large.addEventListener('mouseenter', show)
large.addEventListener('mouseleave', hide)
// 5. 鼠标经过中等盒子,显示隐藏 黑色遮罩层
const layer = document.querySelector('.layer')
middle.addEventListener('mouseenter', function () {
layer.style.display = 'block'
})
middle.addEventListener('mouseleave', function () {
layer.style.display = 'none'
})
// 6.移动黑色遮罩盒子
middle.addEventListener('mousemove', function (e) {
// let x = 10, y = 20
// console.log(11)
// 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标
// console.log(e.pageX)鼠标在页面中的坐标
// middle 中等盒子的坐标
// console.log(middle.getBoundingClientRect().left)
let x = e.pageX - middle.getBoundingClientRect().left
let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop
// console.log(x, y)
// 黑色遮罩移动 在 middle 盒子内 限定移动的距离
if (x >= 0 && x <= 400 && y >= 0 && y <= 400) {
// 黑色盒子不是一直移动的
// 声明2个变量 黑色盒子移动的 mx my变量
let mx = 0, my = 0
if (x < 100) mx = 0
if (x >= 100 && x <= 300) mx = x - 100
if (x > 300) mx = 200
if (y < 100) my = 0
if (y >= 100 && y <= 300) my = y - 100
if (y > 300) my = 200
layer.style.left = mx + 'px'
layer.style.top = my + 'px'
// 大盒子的背景图片要跟随 中等盒子移动 存在的关系是 2倍
large.style.backgroundPositionX = -2 * mx + 'px'
large.style.backgroundPositionY = -2 * my + 'px'
}
})
</script>
</body>
</html>