鼠标的坐标系统太重要了。利用鼠标坐标,可以做好多事情,比如游戏中的鼠标跟随,网页中利用鼠标位置做特效等等。
鼠标坐标的获取,分为两种情况来讨论。
1. 只有一个标签,没有子标签的情况
这种情况最简单,利用事件对象 event 的 offsetX 和 offsetY 属性可以获取鼠标在该标签中的坐标。
问:为什么要用事件对象?
答:因为鼠标坐标的获取往往跟鼠标事件有关联。
举个例子:
<style>
.box{
width: 400px;
height: 400px;
background: #ccc;
margin-left: auto;
margin-right: auto;
}
</style>
<div class="box" id="box">
这个是内容
</div>
<script>
let box = document.getElementById("box");
box.addEventListener("click",function(event){
console.info( event.offsetX, event.offsetY );
});
</script>
鼠标点 box 的任意位置,都会在控制台中输出对应的坐标。
例子嘛,可以做一个 canvas 绘图板。有兴趣的朋友可以试试。
我的一个课程视频,里就说了这个案例:https://v.huya.com/play/291503364.html
2. 包含子标签的情况
利用事件对象 event 的 offsetX,offsetY 属性,如果目标里面有子标签,得到的就是相对子标签的坐标。
这就尴尬了~
<style>
.box{
width: 400px;
height: 400px;
background: #ccc;
margin-left: auto;
margin-right: auto;
}
.small{
width: 200px;
background: #666666;
height: 200px;
margin-left: auto;
margin-right: auto;
}
</style>
<div class="box" id="box">
<div class="small" id="small">
</div>
</div>
<script>
let box = document.getElementById("box");
box.addEventListener("click",function(event){
// 如果点在了子标签上,得到的是相对子标签的坐标。
console.info( event.offsetX, event.offsetY );
});
</script>
解决方法:
为了得到在 box 里的坐标,可以利用 box.getBoundingClientRect() 获取box 在窗口中的位置。利用鼠标在窗口中的坐标,减去 box 在窗口的坐标就可以了。
先看下这个 getBoundingClientRect() 是个什么。
<div class="box" id="box">
<div class="small" id="small">
</div>
</div>
<script>
let box = document.getElementById("box");
box.addEventListener("click",function(event){
let sPos = box.getBoundingClientRect();
console.info( sPos );
console.info( sPos.x, sPos.y ); // 输出标签左上角在窗口的坐标。
},true);
</script>
getBoundingClientRect ,字面含义:获取客户端(client,特指浏览器)形成的矩形区域。它可以获取标签在浏览器窗口中的坐标,以及边界值。
鼠标的在浏览器窗口中的坐标很简单,就是事件对象 event 的 clientX 和 clientY 属性。
那么获取鼠标在指定标签中的方式就是:
let box = document.getElementById("box");
box.addEventListener("click",function(event){
let sPos = box.getBoundingClientRect();
// 输出鼠标在标签中的坐标
console.info( event.clientX-sPos.x, event.clientY-sPos.y );
},true);
3. 封装成一个函数
let getMousePostion = function(box,event){
/*
* 返回鼠标在某个标签里的坐标,数组
* box: 某个标签对象
* event: 事件对象
* */
let sPos = box.getBoundingClientRect();
return [ event.clientX-sPos.x, event.clientY-sPos.y ];
};
经典案例1:按住鼠标推动翻转图片
先看效果:为了减少体积,缩小图片,降低了画面质量。
在 div#box 里按住鼠标移动,可以控制图片翻转。
详细代码:不解释了,看注释。
<style>
.box{
width: 800px;
height: 600px;
position: relative;
margin-left: auto;
margin-right: auto;
background: #f2f2f2;
perspective: 500px;
}
.img{
width: 242px;
height: 309px;
overflow: hidden;
position: absolute;
left:50%;
top:50%;
margin-left: -121px;
margin-top:-154.5px;
transition:all 0.2s;
}
</style>
<div class="box" id="box">
<div class="img" id="img">
<img id="pic" src="../images/meinv.png" width="242" height="309" alt="">
</div>
</div>
<script>
// 找标签
let box = document.getElementById("box"); // 标签范围
let img = document.getElementById("img"); // 图片div
let pic = document.getElementById("pic"); // 图片img
// 极端情况,鼠标从 box 左边到右边的距离,就让图片翻转 180deg。
let degreeNum = 180;
// 开始的鼠标 x 位置。
let startPos = 0;
// 开始图片的翻转度。
let startDeg = 0;
// 鼠标移动控制的旋转度
let xDeg = 0;
// 获取鼠标坐标函数
let getMousePostion = function(box,event){
/*
* 返回鼠标在某个标签里的坐标,数组
* box: 某个标签的 id
* event: 事件对象
* */
let sPos = box.getBoundingClientRect();
return [ event.clientX-sPos.x, event.clientY-sPos.y ];
};
// 鼠标移动事件处理
let mouseMoveFun = function(event){
let nowPos = getMousePostion(box,event)[0];
let disX = nowPos - startPos ;
// 鼠标控制的旋转度:鼠标移动距离 / box宽度 * 180
xDeg = disX / box.offsetWidth * degreeNum;
// 图片旋转:起始度+鼠标控制的旋转度
img.style.transform = `rotateY(${startDeg+xDeg}deg)`;
};
// 鼠标按下事件:开始拖动
box.addEventListener("mousedown",function(event){
startPos = getMousePostion(box,event)[0]; // 按下那一瞬间的鼠标坐标
box.addEventListener("mousemove",mouseMoveFun);
});
// 鼠标松开,取消鼠标移动事件,且重新设置图片旋转的起始度。
box.addEventListener("mouseup",function(event){
startDeg = startDeg+xDeg ;
box.removeEventListener("mousemove",mouseMoveFun);
});
// 防止图片被鼠标拖拽
pic.addEventListener("dragstart",function(event){
event.preventDefault();
});
</script>
经典案例2:鼠标滑动控制图片的倾斜度
鼠标在 div#box 里滑动,图片展示对应的倾斜度,不需要按住鼠标。
<style>
.box{
width: 800px;
height: 600px;
position: relative;
margin-left: auto;
margin-right: auto;
background: #f2f2f2;
perspective: 500px;
}
.img{
width: 242px;
height: 309px;
overflow: hidden;
position: absolute;
left:50%;
top:50%;
margin-left: -121px;
margin-top:-154.5px;
transition:all 0.2s;
}
</style>
让图片在 -60deg 到 60deg 之间倾斜。
<div class="box" id="box">
<div class="img" id="img">
<img src="../images/meinv.png" width="242" height="309" alt="">
</div>
</div>
<script>
let box = document.getElementById("box");
let img = document.getElementById("img");
let boxCenter = [400,300]; // box 中心点。
let degreeNum = 60; // 图片的倾斜度
let getMousePostion = function(box,event){
/*
* 返回鼠标在某个标签里的坐标,数组
* box: 某个标签的 id
* event: 事件对象
* */
let sPos = box.getBoundingClientRect();
return [ event.clientX-sPos.x, event.clientY-sPos.y ];
};
box.addEventListener("mousemove",function(event){
let mousePos = getMousePostion(box,event); // 获取鼠标在 box 里的坐标,数组。
let disX = mousePos[0]-boxCenter[0];
let disY = mousePos[1]-boxCenter[1];
let xDeg = disX / boxCenter[0] * degreeNum;
let yDeg = disY / boxCenter[1] * degreeNum;
console.info( xDeg );
img.style.transform = `rotateY(${xDeg}deg) rotateX(${yDeg}deg)`;
});
</script>
经典案例3:伪3D的banner
结合以上知识,可以做一个伪 3D 的banner。
原理:是利用鼠标距离banner 中点的位置,来控制各个元素的位移(translate)和倾斜度(rotateY)。
HTML标签:
<div class="banner" id="banner">
<img class="ren" id="ren" src="images/renwu.png" width="281" height="430" alt="">
<div class="text" id="text">WHITE MOUSE</div>
<img class="bg" id="bg" src="images/bannerbg.jpg" alt="">
</div>
CSS:各个元素重叠,所以 banner 相对定位,banner 里各个元素绝对定位。
*{
margin: 0;
padding: 0;
}
.banner{
width: 1200px;
height: 430px;
overflow: hidden;
margin-left: auto;
margin-right: auto;
position: relative;
transform-style: preserve-3d; /* 3D 效果,写在容器上,把内部变成 3D 空间 */
perspective: 500px; /* 3D 透视,写在容器上 */
background: #ccc;
}
.banner img{
transition:all 0.2s;
}
.bg{
transform: scale(1.1);
}
.ren{
position: absolute;
left:50%;
top:50%;
margin-left: -240px;
margin-top: -214px;
z-index: 2;
transform: translateZ(50px);
}
.text{
z-index: 1;
width: 1200px;
height: 200px;
line-height: 150px;
font-size: 150px;
text-align: center;
position: absolute;
left:50%;
top:50%;
margin-left: -600px;
margin-top: -100px;
color: #fff;
text-shadow: -10px 5px 0 rgba(0,0,0,0.5);
transform: translateZ(20px);
}
// 找标签
let banner = document.getElementById("banner");
let ren = document.getElementById("ren");
let text = document.getElementById("text");
let bg = document.getElementById("bg");
// 相关数据
let bannerCenter = [600,215]; // 中心点
let deg = 2; // 元素最多倾斜 2 度。
let weizhi = [20,10,5]; // ren ,text ,bg。近中远,近点的内容移动距离大点。
// 获取鼠标坐标函数
let getMousePosition = function(box,event){
let pos = box.getBoundingClientRect();
return [ event.clientX - pos.x, event.clientY - pos.y ];
};
let moveFun = function(event){
let mousePosX = getMousePosition(banner, event)[0];
// 关键数据:鼠标跟中点的水平距离
let disX = mousePosX - bannerCenter[0];
// 关键数据:鼠标跟中点的水平距离 / banner宽度一半 。
// 利用这个比例来计算各个元素的倾斜度和位移。
let weizhiBiLi= disX / bannerCenter[0];
ren.style.transform = `translateZ(50px) rotateY(${deg*weizhiBiLi}deg) translateX(${weizhiBiLi*weizhi[0]}px)`;
text.style.transform = `translateZ(20px) rotateY(${deg*weizhiBiLi}deg) translateX(${weizhiBiLi*weizhi[1]}px)`;
bg.style.transform = `scale(1.1) rotateY(${deg*weizhiBiLi}deg) translateX(${weizhiBiLi*weizhi[2]}px)`;
};
// 添加监听事件
banner.addEventListener("mousemove",moveFun);
素材图:
觉得好的点个赞呗~~