效果图
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>放大镜</title>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
.wrapper {
position: relative;
width: 300px;
height: 400px;
margin: 40px;
}
.img-content {
height: 400px;
width: 300px;
}
.img {
width: 300px;
height: 400px;
background: url("https://gd1.alicdn.com/imgextra/i4/2836027429/O1CN01XfQunw24kWqnh2pBg_!!2836027429.png_400x400.jpg") 0 0 no-repeat;
}
.layer {
position: absolute;
left: 0;
top: 0;
cursor: move;
background: url("https://gtms01.alicdn.com/tps/i4/T12pdtXaldXXXXXXXX-2-2.png") repeat scroll 0 0 transparent;
z-index: 99;
display: none;
}
.preview {
position: absolute;
top: 0;
left: 105%;
height: 400px;
width: 400px;
border: 1px solid;
display: none;
overflow: hidden;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="img-content">
<!-- 存放图片的容器 -->
<div class="img"></div>
<!-- 移动的遮罩层 -->
<div class="layer"></div>
</div>
<div class="preview">
<!-- 图片文件 -->
<img src="./1.png" alt="">
</div>
</div>
</body>
<!-- 引入js文件 -->
<script src="./index.js"></script>
</html>
js
在书写之前,我们需要搞清楚放大镜的原理。
鼠标移入时layer的移动操作
如上图所示,我们需要计算出layer移动的最大的top、left和最小的top和left。同时我们还需要根据鼠标的位置计算出layer的top和left。
// 初始化layer的宽高
this.layerWidth = this.wrapper.offsetWidth / this.multiple;
this.layerHeight = this.wrapper.offsetHeight / this.multiple;
this.layer.style.width = this.layerWidth + 'px';
this.layer.style.height = this.layerHeight + 'px';
// 计算layer能移动的最大位置和最小位置
let maxLeft: number = this.wrapper.offsetWidth - this.layerWidth,
maxTop: number = this.wrapper.offsetHeight - this.layerHeight,
minLeft: number = 0, minTop: number = 0;
let {clientX, clientY} = e;
// 取得layer的top和left
let left: number = clientX - this.wrapper.offsetLeft - this.layerWidth / 2;
let top: number = clientY - this.wrapper.offsetTop - this.layerHeight / 2;
// 对layer的top和left做临界值判断
left = (left > maxLeft) ? maxLeft : (left < minLeft ? minLeft : left);
top = (top > maxTop) ? maxTop : (top < minTop ? minTop : top);
鼠标移入时preview的显示
在鼠标移入时,我们需要对layer所选中的区域进行放大显示,其原理即:将所显示的图片以比例放大,然后设置图片的margin。
// 图片以比例放大
img.style.width = this.multiple * this.preview.offsetWidth + 'px';
img.style.height = this.multiple * this.preview.offsetHeight + 'px';
// 设置图片的margin
img.style.marginLeft = -left * this.multiple + 'px';
img.style.marginTop = -top * this.multiple + 'px';
ts 源码
class Zoom {
// 一些必要的dom
private wrapper: HTMLDivElement = document.querySelector('.wrapper');
private imgContent: HTMLDivElement = document.querySelector('.img-content');
private layer: HTMLDivElement = document.querySelector('.layer');
private preview: HTMLDivElement = document.querySelector('.preview');
// layer的宽高
private layerWidth: number;
private layerHeight: number;
// 放大倍数
private readonly multiple: number;
// 默认放大倍数是2倍
constructor(multiple: number = 2) {
this.multiple = multiple;
this.initLayer();
this.addListener()
}
// 初始化layer的宽高:根据放大比例来初始化
private initLayer() {
this.layerWidth = this.wrapper.offsetWidth / this.multiple;
this.layerHeight = this.wrapper.offsetHeight / this.multiple;
this.layer.style.width = this.layerWidth + 'px';
this.layer.style.height = this.layerHeight + 'px'
}
// 添加监听
private addListener(): void {
// 鼠标移入,进行移动的相关操作
this.imgContent.addEventListener('mousemove', (e: MouseEvent) => {
this.move(e)
});
// 鼠标移出使preview和layer都不显示
this.imgContent.addEventListener('mouseleave', () => {
this.hidePreview()
.hideLayer();
})
}
// 鼠标移入的操作
move(e: MouseEvent): void {
// 计算layer能移动的最大位置和最小位置
let maxLeft: number = this.wrapper.offsetWidth - this.layerWidth,
maxTop: number = this.wrapper.offsetHeight - this.layerHeight,
minLeft: number = 0, minTop: number = 0;
let {clientX, clientY} = e;
// 取得layer的top和lft
let left: number = clientX - this.wrapper.offsetLeft - this.layerWidth / 2;
let top: number = clientY - this.wrapper.offsetTop - this.layerHeight / 2;
// 对layer的top和left做临界值判断
left = (left > maxLeft) ? maxLeft : (left < minLeft ? minLeft : left);
top = (top > maxTop) ? maxTop : (top < minTop ? minTop : top);
// 显示layer和preivew
this.showLayer(left, top)
.showPreview(left, top);
}
// 根据top和left显示layer
private showLayer(left?: number, top?: number): Zoom {
this.layer.style.display = 'block';
if (left && top) {
this.layer.style.top = top + 'px';
this.layer.style.left = left + 'px';
}
return this;
}
// 显示preview
showPreview(left?: number, top?: number): Zoom {
this.preview.style.display = 'block';
if (left && top) {
let previewImg: HTMLImageElement = <HTMLImageElement>this.preview.children[0];
this.zoomImg(previewImg)
.moveImg(previewImg, top, left);
}
return this;
}
// 放大显示的图片
private zoomImg(img: HTMLImageElement): Zoom {
img.style.width = this.multiple * this.preview.offsetWidth + 'px';
img.style.height = this.multiple * this.preview.offsetHeight + 'px';
return this;
}
// 移动图片,即设置图片的marginLeft和marginTop
private moveImg(img: HTMLImageElement, top: number, left: number): Zoom {
img.style.marginLeft = -left * this.multiple + 'px';
img.style.marginTop = -top * this.multiple + 'px';
return this;
}
// none掉layer
private hideLayer(): Zoom {
this.layer.style.display = 'none';
return this
}
// none掉preview
private hidePreview(): Zoom {
this.preview.style.display = 'none';
return this
}
}
new Zoom();