- 元素获取
- 鼠标事件
- 比例设置
- 边界检测
一、HTML部分
<div class="container">
<!-- 左侧图片部分 -->
<div class="img">
<img src="./images/1.jpg" alt="">
<!-- 焦点框 -->
<div class="focus"></div>
</div>
<!-- 左侧小图列表 -->
<div class="list">
<div class="button-prev"><</div>
<div class="button-next">></div>
<span class="active">
<img src="./images/1.small.jpg" alt="">
</span>
<span>
<img src="./images/2.small.jpg" alt="">
</span>
<span class>
<img src="./images/1.small.jpg" alt="">
</span>
<span>
<img src="./images/2.small.jpg" alt="">
</span>
</div>
<!-- 右侧放大图片部分 -->
<div class="big-img">
<img src="./images/1.big.jpg" alt="">
</div>
</div>
二、CSS部分
<style>
* {
margin: 0;
padding: 0;
}
.container {
width: 350px;
margin-left: 100px;
position: relative;
}
.img {
width: 350px;
height: 350px;
}
.img img {
width: 100%;
height: 100%;
}
.focus {
border: 1px solid #aaa;
background: no-repeat #fede4f;
opacity: .5;
cursor: move;
position: absolute;
left: 0;
top: 0;
z-index: 9;
display: none;
}
.big-img {
width: 540px;
height: 540px;
position: absolute;
left: 350px;
top: 0;
/* 关键 */
overflow: hidden;
display: none;
}
.big-img img {
width: 800px;
height: 800px;
position: absolute;
}
.list span {
display: inline-block;
border: 2px solid #fff;
margin-left: 5px;
}
.list span.active {
border-color: #f10;
}
.list span:hover {
border-color: #f10;
}
.list {
width: 100%;
position: relative;
padding-left: 40px;
}
.button-next,
.button-prev {
width: 30px;
height: 30px;
position: absolute;
left: 0;
background-color: skyblue;
top: 50%;
margin-top: -15px;
text-align: center;
line-height: 30px;
}
.button-next:hover,
.button-prev:hover {
opacity: .7;
cursor: pointer;
}
.button-next {
left: 100%;
margin-left: -70px;
}
</style>
三、JS部分
- offset:
- 从当前元素开始逐层向父级进行查找, 如果有带有position属性的元素,那么就以这个元素为参照,如果查找到了body依旧没有找到参照物,那么就以body为参照物。
只能取值,不能赋值
以距离鼠标最近的元素为参照物定位的 鼠标位置
- client:
- 以浏览器可视区边缘为参照物定位的 鼠标位置
<script>
// 鼠标移入事件:显示(焦点,大图)
// 鼠标移出事件:隐藏(焦点,大图)
// 列表鼠标移入:切换图片
// --解决方法:在布局时将focus框放入img盒子
// 初始化布局时,放大镜(正常图片)和焦点框的比例非常重要,目前定义为:1:0.6
class Magnifier {
constructor() {
this.img = document.querySelector(".img")
this.focus = document.querySelector(".focus")
this.big_img = document.querySelector(".big-img")
this.big_bg = document.querySelector(".big-img img")
// 为了获取元素的偏移距离,计算正确的focus位置
this.scale = 0.6
this.container = document.querySelector(".container")
// 切换图片的元素
this.btns = document.querySelectorAll(".list span")
// 切换图片按钮
this.next_button = document.querySelector(".button-next")
this.prev_button = document.querySelector(".button-prev")
// 存储自动播放定时器返回值的变量
this.autopaly_interval = null
// 切换小图行为核心数据
this.index = 0
// 图片数据
this.img_list = [
{
small: "./images/1.jpg",
big: "./images/1.big.jpg"
},
{
small: "./images/2.jpg",
big: "./images/2.big.jpg"
},
{
small: "./images/1.jpg",
big: "./images/1.big.jpg"
},
{
small: "./images/2.jpg",
big: "./images/2.big.jpg"
}
]
this.init()
this.c_off = {
left: this.container.offsetLeft,
top: this.container.offsetTop
}
// offset家族不能测量display为none的元素,改用getComputedStyle
this.f_style = getComputedStyle(this.focus)
this.i_style = getComputedStyle(this.img)
// focus边界数据对象
this.boundary = {
x: {
min: 0,
max: parseInt(this.i_style.width) - parseInt(this.f_style.width)
},
y: {
min: 0,
max: parseInt(this.i_style.height) - parseInt(this.f_style.height)
}
}
this.bindEvent()
}
init() {
// 为了让图片跟随更精准
this.focus.style.width = 350 * this.scale + "px"
this.focus.style.height = 350 * this.scale + "px"
this.big_img.style.width = 800 * this.scale + "px"
this.big_img.style.height = 800 * this.scale + "px"
}
bindEvent() {
this.img.addEventListener("mouseover", () => {
this.show()
})
this.img.addEventListener("mouseout", () => {
this.hide()
})
this.img.addEventListener("mousemove", (e) => {
// 浏览器可视区域左上角获取的x,y,需要进行处理
// 如果使用offset会出现鼠标获取位置的参照物和focus元素定位的参照物不一致
this.move(e.clientX, e.clientY)
})
for (let i = 0; i < this.btns.length; i++) {
this.btns[i].addEventListener("mouseenter", () => {
this.index = i
this.change()
})
}
this.next_button.addEventListener("click", () => {
this.add()
})
this.prev_button.addEventListener("click", () => {
this.reduce()
})
}
show() {
this.focus.style.display = "block"
this.big_img.style.display = "block"
}
hide() {
this.focus.style.display = "none"
this.big_img.style.display = "none"
}
move(x, y) {
// 减parseInt(this.f_style.width)/2是为了让鼠标的位置位于focus框中间
x = x - this.c_off.left - parseInt(this.f_style.width) / 2
y = y - this.c_off.top - parseInt(this.f_style.height) / 2
// 边界检测
x = x <= this.boundary.x.min ? this.boundary.x.min : x
x = x >= this.boundary.x.max ? this.boundary.x.max : x
y = y <= this.boundary.y.min ? this.boundary.y.min : y
y = y >= this.boundary.y.max ? this.boundary.y.max : y
this.focus.style.left = x + "px"
this.focus.style.top = y + "px"
this.big_bg.style.left = -x * (800 / 350) + "px"
this.big_bg.style.top = -y * (800 / 350) + "px"
}
change() {
this.btns.forEach(ele => ele.classList.remove("active"))
this.btns[this.index].classList.add("active")
this.img.children[0].src = this.img_list[this.index].small
this.big_bg.src = this.img_list[this.index].big
}
add() {
// 获取正确下标
if (this.index === this.btns.length - 1) {
this.index = 0
} else {
this.index++
}
this.change()
}
reduce() {
if (this.index <= 0) {
this.index = this.btns.length - 1
} else {
this.index--
}
this.change()
}
autoPlay() {
this.autopaly_interval = setInterval(() => {
this.add()
}, 5000)
}
}
var m = new Magnifier
m.autoPlay()
</script>
放大镜所用图片:图片资源(免费)