学习目标:
- 掌握案例-放大镜效果
学习内容:
- 业务分析
- 思路分析
- 放大镜完整代码
业务分析:
- 鼠标经过对应小盒子,左侧中等盒子显示对应中等图片;
- 鼠标经过中盒子,右侧会显示放大镜效果的大盒子;
- 黑色遮罩盒子跟着鼠标来移动;
- 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置。
思路分析:
- 鼠标经过小盒子,左侧中等盒子显示对应中等图片:
-
获取对应的元素。
-
采取事件委托的形式,监听鼠标经过小盒子里面的图片, 注意此时需要使用
mouseover
事件,因为需要事件冒泡触发small
。 -
让鼠标经过小图片的爸爸
li
盒子,添加类,其余的li
移除类(注意先移除,后添加)。 -
鼠标经过小图片,可以拿到小图片的
src
, 可以做两件事:让中等盒子的图片换成这个 这个小图片的src 让大盒子的背景图片,也换成这个小图片的 src (稍后做)
//获取三个盒子//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(11)//排他 干掉以前的active li 上面this.querySelector('.active').classList.remove('active')//当前元素的爸爸添加activee.target.parentNode.classList.add('active')//拿到当前小图片的src// console.log(e.target.src)//让中盒子里面的图片 ,src更换为 小图片srcmiddle.querySelector('img').src = e.target.src//大盒子更换背景图片large.style.backgroundImage = `url(${e.target.src})`}})
- 鼠标经过中等盒子,右侧大盒子显示:
- 用到鼠标经过和离开,鼠标经过中盒子,大盒子 利用
display
来显示和隐藏。 - 鼠标离开不会立马消失,而是有200ms的延时,用户体验更好,所以尽量使用定时器做个延时
setTimeout
。 - 显示和隐藏也尽量定义一个函数,因为鼠标经过离开中等盒子,会显示隐藏,同时,鼠标经过大盒子,也会显示和隐藏。
- 给大盒子里面的背景图片一个默认的第一张图片。
//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)}
- 黑色遮罩盒子跟着鼠标来移动:
- 先做鼠标经过中等盒子,显示隐藏黑色遮罩的盒子。
- 让黑色遮罩跟着鼠标来走, 需要用到鼠标移动事件
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 之间移动的。
垂直同理。
let mx = 0, my = 0;
if (x <= 100) mx = 0
if (x > 100 && x < 300) mx = x - 100
if (x >= 300) mx = 200if (y <= 100) my = 0
if (y > 100 && y < 300) my = y - 100
if (y >= 300) my = 200
大盒子图片移动的计算方法:
中等盒子是 400px 大盒子 是 800px 的图片。
中等盒子移动1px, 大盒子就应该移动2px, 只不过是负值。
large.style.backgroundPositionX = - 2 * mx + 'px'
large.style.backgroundPositionY = - 2 * my + 'px'
//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 = 20, y = 20// console.log(11)//鼠标在middle盒子里面的坐标 = 鼠标在页面中的坐标 - middle中等盒子的坐标// console.log(e.pageX)鼠标在页面中的坐标//middle 中等盒子的坐标// console.log(middle.getBoundingClientRect().left)let x = e.pageX - middle.getBoundingClientRect().leftlet 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 = 0if (x < 100) mx = 0if (x >= 100 && x <= 300) mx = x - 100if (x > 300) mx = 200if (y < 100) my = 0if (y >= 100 && y <= 300) my = y - 100if (y > 300) my = 200layer.style.left = mx + 'px'layer.style.top = my + 'px'//大盒子的背景图片要跟随 中等盒子移动 存在的关系是2倍large.style.backgroundPositionX = -2 * mx + 'px'large.style.backgroundPositionY = -2 * my + 'px'}
放大镜完整代码:
<script>//获取三个盒子//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(11)//排他 干掉以前的active li 上面this.querySelector('.active').classList.remove('active')//当前元素的爸爸添加activee.target.parentNode.classList.add('active')//拿到当前小图片的src// console.log(e.target.src)//让中盒子里面的图片 ,src更换为 小图片srcmiddle.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 = 20, y = 20// console.log(11)//鼠标在middle盒子里面的坐标 = 鼠标在页面中的坐标 - middle中等盒子的坐标// console.log(e.pageX)鼠标在页面中的坐标//middle 中等盒子的坐标// console.log(middle.getBoundingClientRect().left)let x = e.pageX - middle.getBoundingClientRect().leftlet 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 = 0if (x < 100) mx = 0if (x >= 100 && x <= 300) mx = x - 100if (x > 300) mx = 200if (y < 100) my = 0if (y >= 100 && y <= 300) my = y - 100if (y > 300) my = 200layer.style.left = mx + 'px'layer.style.top = my + 'px'//大盒子的背景图片要跟随 中等盒子移动 存在的关系是2倍large.style.backgroundPositionX = -2 * mx + 'px'large.style.backgroundPositionY = -2 * my + 'px'}})</script>