一、 offset相关概念
offsetLeft: 指相对于带有定位的父级元素左侧偏移量(若无则以body为基准)
offsetTop: 指相对于带有定位的父级元素上方偏移量
offsetWidth:自身的width + padding + border 只读
offsetHeight:自身的height + padding + border 只读
ps:
1. clientWidth与clientHeight 不包含边框border大小,clientTop与clientLeft分别取上边框与左边框大小
2. scrollWidth与scrollHeight返回实际宽高(不包括border),scrollTop与scrollLeft返回元素被卷入的上边和左边的距离(页面被卷去的头部可以用window.pageYOffset获得)
3. window.scroll(x, y) -- 页面滚动
demo:计算鼠标点击盒子时,距离盒子的位置
var box = document.querySelector('.box');
box.addEventListener('click', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
console.log(x,y);
})
二、拖动模态框
图示:先思考大盒子需要移动的距离怎么算的:
1. 鼠标按下时:鼠标的pageX - 大盒子的offsetLeft ->鼠标在大盒子内的距离(之后都不变)
2. 鼠标移动时:鼠标的pageX - 鼠标在大盒子内的距离(之前求过的)
3. 鼠标松开时:要移除move事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
.bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .2);
display: none;
}
button,.close {
cursor: pointer;
}
.login {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 300px;
padding: 20px 0;
z-index: 1;
text-align: center;
background-color: #fff;
display: none;
}
.close {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
line-height: 20px;
font-size: 20px;
}
h2 {
margin-bottom: 15px;
cursor: move;
}
</style>
</head>
<body>
<button>点击弹出登录框</button>
<div class="login">
<span class="close">x</span>
<h2>登录</h2>
用户名:<input type="text" placeholder="请输入用户名"><br/>
密码:<input type="password" name="" id="" placeholder="请输入密码"><br/>
</div>
<div class="bg"></div>
<script>
var btn = document.querySelector('button');
var login = document.querySelector('.login');
var bg = document.querySelector('.bg');
var close = document.querySelector('.close');
var chooseArea = document.querySelector('h2');
btn.addEventListener('click', function() {
login.style.display = 'block';
bg.style.display = 'block';
})
close.addEventListener('click', function() {
login.style.display = 'none';
bg.style.display = 'none';
})
chooseArea.addEventListener('mousedown', function(e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
document.addEventListener('mousemove', fn);
function fn(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', fn);
})
})
</script>
</body>
</html>
三、放大镜效果
1. 思想:鼠标在大盒子内的距离相当于遮罩层mask在大盒子里的距离
注意这段代码有两个问题:
1. 鼠标应该放在mask层中间,而不是一直在左上角;
2. mask可以被移到大盒子的外面。
smallArea.addEventListener('mousemove', function(e) {
var maskX = e.pageX - smallArea.offsetLeft;
var maskY = e.pageY - smallArea.offsetTop;
mask.style.top = maskY + 'px';
mask.style.left = maskX + 'px';
})
修改过后:
//第二步: 让遮罩层随着鼠标移动,并且调整移出盒子时的移动量
smallArea.addEventListener('mousemove', function(e) {
var x = e.pageX - smallArea.offsetLeft;
var y = e.pageY - smallArea.offsetTop;
var maxX = smallArea.offsetWidth - mask.offsetWidth;
var maxY = smallArea.offsetHeight - mask.offsetHeight;
var maskX = x - mask.offsetWidth/2;
var maskY = y - mask.offsetHeight/2;
if(maskX < 0 ) {
maskX = 0;
}else if(maskX >= maxX) {
maskX = maxX;
}
if(maskY < 0) {
maskY = 0;
}else if(maskY >= maxY) {
maskY =maxY;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
})
2. 思想:由于遮罩层mask移动的距离与右侧大盒子内的图片移动距离并不能同等,需要用比例来求出右侧大盒子内的图片移动的距离。公式为:
mask移动距离 / mask能移动的最大距离 = 大图片移动距离 / 大图片能移动的最大距离
∴ 大图片移动距离 = mask移动距离 * 大图片能移动的最大距离 /mask能移动的最大距离
//大盒子能移动的最大距离
var maxBigBoxX = bigPic.offsetWidth - magnifyArea.offsetWidth;
var maxBigBoxY = bigPic.offsetHeight - magnifyArea.offsetHeight;
bigPic.style.left = - maskX * maxBigBoxX / maxX + 'px';
bigPic.style.top = - maskY * maxBigBoxY / maxY + 'px';
整个放大镜效果的代码为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
.example {
margin: 20px auto;
padding: 30px;
}
.smallArea {
position: relative;
width: 400px;
height: 400px;
border: 1px solid #ccc;
}
.smallPic {
width: 100%;
}
.magnifyArea {
position: absolute;
top: 0;
left: 420px;
width: 500px;
height: 500px;
border: 1px solid #ccc;
display: none;
overflow: hidden;
}
.bigPic {
position: absolute;
}
.mask {
position: absolute;
top: 0;
left: 0;
width: 227px;
height: 227px;
background-color: yellowgreen;
opacity: .3;
cursor: move;
display: none;
}
</style>
</head>
<body>
<div class="example">
<div class="smallArea">
<img src="./images/small.png" class="smallPic">
<div class="mask"></div>
<div class="magnifyArea">
<img src="./images/big.jpg" class="bigPic">
</div>
</div>
</div>
<script>
var smallArea = document.querySelector('.smallArea');
var mask = document.querySelector('.mask');
var magnifyArea = document.querySelector('.magnifyArea');
var bigPic = document.querySelector('.bigPic');
//第一步: 显示遮罩层以及放大镜
smallArea.addEventListener('mouseover', function() {
mask.style.display = 'block';
magnifyArea.style.display = 'block';
})
smallArea.addEventListener('mouseout', function() {
mask.style.display = 'none';
magnifyArea.style.display = 'none';
})
//第二步: 让遮罩层随着鼠标移动,并且调整移出盒子时的移动量
smallArea.addEventListener('mousemove', function(e) {
var x = e.pageX - smallArea.offsetLeft;
var y = e.pageY - smallArea.offsetTop;
//mask能移动的最大距离
var maxX = smallArea.offsetWidth - mask.offsetWidth;
var maxY = smallArea.offsetHeight - mask.offsetHeight;
var maskX = x - mask.offsetWidth/2;
var maskY = y - mask.offsetHeight/2;
if(maskX < 0 ) {
maskX = 0;
}else if(maskX >= maxX) {
maskX = maxX;
}
if(maskY < 0) {
maskY = 0;
}else if(maskY >= maxY) {
maskY =maxY;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
//大盒子能移动的最大距离
var maxBigBoxX = bigPic.offsetWidth - magnifyArea.offsetWidth;
var maxBigBoxY = bigPic.offsetHeight - magnifyArea.offsetHeight;
bigPic.style.left = - maskX * maxBigBoxX / maxX + 'px';
bigPic.style.top = - maskY * maxBigBoxY / maxY + 'px';
})
</script>
</body>
</html>