一、需求说明
1、鼠标移入图片显示遮罩层和右边的放大镜
鼠标移出图片隐藏遮罩层和右边的放大镜
2、鼠标经过下面的图片列表区切换显示的图片
3、鼠标在显示的图片上移动,遮罩层也会跟着移动,并且放大的图片也会跟着对应移动
二、核心代码
// 放大镜构造函数
// 参数1 生成放大镜内容的标签对象
// 参数2 放大镜参数数据数组
class setGlass {
constructor(element, array) {
// 定义属性存储参数
this.ele = element;
this.arr = array;
// 定义属性存储数据
this.show;
this.img;
this.mask;
this.list;
this.listLiImg;
this.glass;
}
// 入口函数
init() {
// 入口函数中调用所有需要执行的函数程序
this.setPage();
this.setMouseOver();
this.setMouseMove();
}
// 动态生成页面
setPage() {
// 创建标签对象
this.show = document.createElement('div');
this.mask = document.createElement('div');
this.glass = document.createElement('div');
this.img = document.createElement('img');
this.list = document.createElement('ul');
// 设定标签对象的相关属性
// 显示区 设定 class选择器
this.show.classList.add('show');
this.mask.classList.add('mask');
this.list.classList.add('list');
this.glass.classList.add('glass');
// 图片标签 默认显示 数组中 第一组数据中 large图片
this.img.setAttribute('src', `./images/${this.arr[0].large}`);
// 图片标签 添加name属性值
this.img.setAttribute('name', 'showImg');
this.mask.setAttribute('name', 'showImg');
// 显示区中 有 图片标签 和 遮盖层标签
this.show.appendChild(this.img);
this.show.appendChild(this.mask);
// 给 this.show 这个节点 直接 绑定事件
// 绑定好事件之后 再 执行写入操作
// 之后 即使 再次动态渲染生成页面 也是 创建新的this.show节点 同时绑定事件 再写入节点
this.show.addEventListener('mouseenter', () => {
// 移入 让 遮盖层 和 放大镜 显示
this.mask.style.display = 'block';
this.glass.style.display = 'block';
})
this.show.addEventListener('mouseleave', () => {
// 移入 让 遮盖层 和 放大镜 隐藏
this.mask.style.display = 'none';
this.glass.style.display = 'none';
})
// 根据数组生成 list 中 li 标签对象
let liStr = '';
this.arr.forEach((item, key) => {
liStr += key === 0 ? `<li><img name="liImg" class="active" index="${key}" src="./images/${item.small}" alt=""></li>` : `<li><img name="liImg" index="${key}" src="./images/${item.small}" alt=""></li>`
})
// 将 字符串 写入 list,ul标签中
this.list.innerHTML = liStr;
// 将 标签对象 写入 box,div标签 中
this.ele.appendChild(this.show);
this.ele.appendChild(this.list);
this.ele.appendChild(this.glass);
// 将 标签对象 写入 box,div标签 之后
// 获取 list 标签中的 li标签 中的 img标签
this.listLiImg = this.list.querySelectorAll('li>img');
}
// 鼠标 移入 图片
// 只有 移入没有移出 可以 事件委托添加给 图片标签
setMouseOver() {
// 给 父级div标签 添加 鼠标移入事件
this.ele.addEventListener('mouseover', e => {
// 如果 移入的标签 name 是 liImg 证明 移入的是 列表 图片标签
if (e.target.getAttribute('name') === 'liImg') {
// 1 清除其他的img标签 class,active 给 移入的img标签添加 class,active
// 循环遍历 所有的 li>img 清除 class,active
this.listLiImg.forEach(item => {
// item 就是 图片标签对象
item.classList.remove('active');
})
// 给经过的 li>img 添加 class,active
e.target.classList.add('active');
// 2 设定 show显示区域中img标签src属性
// 是 鼠标进过的 li>img 标签 index属性中 存储的索引下标
this.img.setAttribute('src', `./images/${this.arr[Number(e.target.getAttribute('index'))].large}`);
// 3 设定 glass放大镜中背景图片的css样式
this.glass.style.backgroundImage = `url('./images/${this.arr[Number(e.target.getAttribute('index'))].large}')`;
}
})
}
// 鼠标 拖住效果
setMouseMove() {
// 如果视窗窗口大小改变,刷新页面
window.addEventListener('resize', function () {
window.location.reload();
})
// 获取 数据
// 获取 box,div的 外间距
let oBoxLeft = this.ele.offsetLeft;
let oBoxTop = this.ele.offsetTop;
// 获取 show,div的 边框线
let oShowBorderLeft = this.show.clientLeft;
let oShowBorderTop = this.show.clientTop;
// 获取 show,div的 占位 内容+padding
// 用来设置极值
let oShowWidth = this.show.clientWidth;
let oShowHeight = this.show.clientHeight;
console.log(oShowWidth);
let oShowWidth1 = this.show.offsetWidth;
let oShowHeight1 = this.show.offsetHeight;
// 获取 mask,div的 占位 内容+padding+border
let oMaskWidth = parseInt(window.getComputedStyle(this.mask).width);
let oMaskHeight = parseInt(window.getComputedStyle(this.mask).height);
// 给 父级div标签 添加 鼠标移动事件
// 如果 是 在 show,div 中 img标签 触发移动事件 执行 鼠标拖拽效果
this.ele.addEventListener('mousemove', e => {
// 事件对象标签 name 是 showImg 证明 触发的标签是 show,div中的img标签
if (e.target.getAttribute('name') === 'showImg') {
// 1, 计算设定 遮盖层定位数据
let x = e.pageX - oBoxLeft - oShowBorderLeft - oMaskWidth / 2;
let y = e.pageY - oBoxTop - oShowBorderTop - oMaskHeight / 2;
// 2, 设定极值
x = x < 0 ? 0 : x;
y = y < 0 ? 0 : y;
x = x > oShowWidth - oMaskWidth ? oShowWidth - oMaskWidth : x;
y = y > oShowHeight - oMaskHeight ? oShowHeight - oMaskHeight : y;
// 3, 将 遮盖层定位赋值
this.mask.style.left = x + 'px';
this.mask.style.top = y + 'px';
// 4, 设定 背景图片定位数值
// 和 遮盖层定位数值方向相反 比例关系 是 2.5 倍
this.glass.style.backgroundPosition = `${-x * 2.5}px ${-y * 2.5}px`;
}
})
}
}
三、解释说明
放大镜
1, 放大镜 默认起始显示 第一组图片内容
2, 放大镜div中显示的 背景图片
3, 各个区域内容的原始比例关系
遮盖层 放大镜
-------- = -----------
显示区 背景图片
-
重点内容:外部
js
文件中的相对路径 不是写外部
js
文件的相对路径,写的是加载执行这个js
文件的html
文件的相对路径,意思就是:js
里面的图片路径是从这个html
文件出发去寻找图片的,而不是从js
出发。 -
重点内容:子级标签添加鼠标移入移出事件
不能通过事件委托给父级标签添加事件,实现子级标签的移入、移出;因为子级标签触发
over
移入的同时也会触发父级标签的out
移出事件。 在创建标签时直接给创建的子级标签节点添加事件,添加好事件之后,将标签节点写入,也就是每次写入的节点都是绑定好事件的节点。
-
给列表区中的 img标签添加鼠标移入事件
只有鼠标移入,没有鼠标移出,因此可以通过事件委托的语法形式给 img标签添加事件。
需要注意:
- img标签设定的是标签的 src属性的属性值
- div标签设定的是 backgroundImage背景图片的路径样式
-
鼠标拖动效果
获取数据:
-
display: none / 绝对定位 / 固定定位 的标签,没有占位大小,
-
只能通过标签的 css 样式属性获取占位大小。在获取 mask的占位时用到了。
-
遮盖层移动和背景图片移动的比例关系
-
遮盖层移动和背景图片移动方向相反
-
移动数值成等比例关系
遮盖层 显示区 遮盖层定位
---------- = ------------- = ------------------
放大镜 背景图片 背景图片定位
-
比例关系怎么确定?
- 若遮罩层移动到最右边,那么背景图要移动到最左边
- 遮罩层到最右边需要移动 显示区的大小(400) - 遮罩层的大小(200) = 200
- 背景图到最左边需要移动 背景图的大小(1000) - 放大镜的大小(500) = 500
- 他们移动距离的比值是:200/500 = 1/2.5
-
-