Part1鼠标事件类型
这些是 JavaScript 中与鼠标事件相关的常见事件类型。具体介绍如下:
auxclick:表示鼠标的辅助按键被点击。辅助按键包括鼠标中键和右键。click:表示鼠标单击操作被触发。dblclick:表示鼠标双击操作被触发。mousedown:表示鼠标按下操作被触发。mouseup:表示鼠标松开操作被触发。mouseover:表示鼠标移动到某个元素之上时被触发。mousemove:表示鼠标在某个元素上移动时被触发。mouseout:表示鼠标移出某个元素时被触发。mouseenter:表示鼠标进入某个元素时被触发。与mouseover不同,mouseenter不会在鼠标从元素的子元素进入时触发。mouseleave:表示鼠标离开某个元素时被触发。与mouseout不同,mouseleave不会在鼠标进入元素的子元素时触发。mousewheel:表示鼠标滚轮被滚动时被触发。该事件在不同浏览器中的表现可能有所不同。wheel:表示鼠标滚轮被滚动时被触发,与mousewheel类似。但是,wheel事件提供更多的信息,比如滚动的距离和方向。contextmenu:表示鼠标右键菜单被触发。
1鼠标位置
| 属性 | 说明 | 兼容性 |
|---|---|---|
| clientX | 以浏览器窗口左上顶角为原点,定位 x 轴坐标 | 所有浏览器,不兼容 Safari |
| clientY | 以浏览器窗口左上顶角为原点,定位 y 轴坐标 | 所有浏览器,不兼容 Safari |
| offsetX | 以当前事件的目标对象左上顶角为原点,定位 x 轴坐标 | 所有浏览器,不兼容 Mozilla |
| offsetY | 以当前事件的目标对象左上顶角为原点,定位 y 轴坐标 | 所有浏览器,不兼容 Mozilla |
| pageX | 以 document 对象(即文档窗口)左上顶角为原点,定位 x 轴坐标 | 所有浏览器,不兼容 IE |
| pageY | 以 document 对象(即文档窗口)左上顶角为原点,定位 y 轴坐标 | 所有浏览器,不兼容 IE |
| screenX | 计算机屏幕左上顶角为原点,定位 x 轴坐标 | 所有浏览器 |
| screenY | 计算机屏幕左上顶角为原点,定位 y 轴坐标 | 所有浏览器 |
| layerX | 最近的绝对定位的父元素(如果没有,则为 document 对象)左上顶角为元素,定位 x 轴坐标 | Mozilla 和 Safari |
| layerY | 最近的绝对定位的父元素(如果没有,则为 document 对象)左上顶角为元素,定位 y 轴坐标 | Mozilla 和 Safari |
2获取鼠标坐标
-
鼠标移动事件:
当鼠标在页面上移动时,通过event对象的pageX和pageY属性获取当前鼠标坐标。
document.addEventListener("mousemove", function(event){
var x = event.pageX;
var y = event.pageY;
console.log("鼠标坐标为:" + x + ", " + y);
});
-
鼠标单击事件:
当鼠标在页面上单击时,通过event对象的clientX和clientY属性获取当前鼠标坐标。
document.addEventListener("click", function(event){
var x = event.clientX;
var y = event.clientY;
console.log("鼠标单击坐标为:" + x + ", " + y);
});
注意:clientX和clientY属性是相对于当前窗口的位置,而pageX和pageY是相对于整个文档的位置。
3在鼠标静止不动时获取坐标
你可以使用 mousemove 事件监听鼠标移动,然后使用 setTimeout 和 setInterval 函数来判断鼠标是否停止移动。在鼠标停止移动的时候,就可以获取当前鼠标的位置坐标了。以下是示例代码:
var timer = null;
var lastX = null;
var lastY = null;
function onMouseMove(e) {
var x = e.clientX;
var y = e.clientY;
if (lastX === null && lastY === null) {
// 第一次移动
lastX = x;
lastY = y;
return;
}
if (x === lastX && y === lastY) {
// 鼠标停止移动
clearInterval(timer);
console.log('鼠标坐标:', lastX, lastY);
} else {
// 继续移动
lastX = x;
lastY = y;
}
}
document.addEventListener('mousemove', function(e) {
clearTimeout(timer);
timer = setInterval(function() {
onMouseMove(e);
}, 50);
});
这段代码会监听鼠标移动事件,每当鼠标移动时,会清除定时器和设置新的定时器,定时器的作用是每隔一段时间(这里是50毫秒)检查鼠标移动是否停止。如果鼠标停止移动,就会清除定时器并打印输出鼠标坐标。
Part2鼠标移动轨迹可视化
思路:当鼠标在页面上移动时,动态创建一个小圆点(位置就是鼠标的当前位置)。一秒后,再把该圆点删除掉。仅需要js代码就能实现。
//鼠标移动时,动态创建div,一秒后删除
window.onmousemove = function(event) {
var nDiv = document.createElement('div')
//创建新的div
var e = event || window.event
//获取事件对象
//设置div的样式(红色小圆点)和位置(鼠标当前位置)
nDiv.style.cssText = "position:absolute; width:5px; height:5px; border-radius:50%"
nDiv.style.left = e.pageX + "px"
nDiv.style.top = e.pageY + "px"
//把创建好的div添加到body里面
document.body.appendChild(nDiv)
//延迟定时器实现一秒后删除效果
setTimeout(function() {
nDiv.remove();
}, 1000)
}
4写法1
function handleEvent(event) {
var nDiv = document.createElement('div')
var e = event || window.event
if (event.type === 'mousemove') {
nDiv.style.cssText = "position:absolute; width:5px; height:5px; border-radius:50%; z-index:9999; pointer-events:none"
} else if (event.type === 'mousedown') {
nDiv.style.cssText = "position:absolute; width:10px; height:10px; border-radius:50%; z-index:10000; pointer-events:none"
} else if (event.type === 'mouseup') {
nDiv.style.cssText = "position:absolute; width:100px; height:100px; border-radius:50%; z-index:10001; pointer-events:none"
} else if (event.type === 'click') {
nDiv.style.cssText = "position:absolute; width:10px; height:10px; border-radius:50%; z-index:10002; pointer-events:none"
}
nDiv.style.left = e.pageX + "px"
nDiv.style.top = e.pageY + "px"
document.body.appendChild(nDiv)
setTimeout(function() {
nDiv.remove();
}, 1000)
}
window.onmousemove = handleEvent
window.onmousedown = handleEvent
window.onmouseup = handleEvent
window.onclick = handleEvent
5写法2
window.onmousemove = function(event) {
var nDiv = document.createElement('div')
var e = event || window.event
nDiv.style.cssText = "position:absolute; width:5px; height:5px; border-radius:50%; z-index:9999; pointer-events:none"
nDiv.style.left = e.pageX + "px"
nDiv.style.top = e.pageY + "px"
document.body.appendChild(nDiv)
setTimeout(function() {
nDiv.remove();
}, 1000)
}
window.onclick = function(event) {
var nDiv = document.createElement('div')
var e = event || window.event
nDiv.style.cssText = "position:absolute; width:10px; height:10px; border-radius:50%; z-index:10002; pointer-events:none"
nDiv.style.left = e.pageX + "px"
nDiv.style.top = e.pageY + "px"
document.body.appendChild(nDiv)
setTimeout(function() {
nDiv.remove();
}, 1000)
}
6写法3(推荐)
window.addEventListener('mousemove', function(event) {
var nDiv = document.createElement('div')
var e = event || window.event
nDiv.style.cssText = "position:absolute; width:5px; height:5px; border-radius:50%; z-index:9999; pointer-events:none"
nDiv.style.left = e.pageX + "px"
nDiv.style.top = e.pageY + "px"
document.body.appendChild(nDiv)
setTimeout(function() {
nDiv.remove();
}, 1000)
});
window.addEventListener('click', function(event) {
var nDiv = document.createElement('div')
var e = event || window.event
nDiv.style.cssText = "position:absolute; width:10px; height:10px; border-radius:50%; z-index:10002; pointer-events:none"
nDiv.style.left = e.pageX + "px"
nDiv.style.top = e.pageY + "px"
document.body.appendChild(nDiv)
setTimeout(function() {
nDiv.remove();
}, 1000)
});
7针对元素滑块
如果你想在滑块元素上记录鼠标的按下和移动事件,你可以尝试以下的代码:
var sliderElements = document.getElementsByClassName('passMod_slide-btn ');
var sliderElement = sliderElements[0];
sliderElement.addEventListener('mousedown', function(event) {
console.log('Mouse down at:', event.clientX, event.clientY);
});
sliderElement.addEventListener('mousemove', function(event) {
console.log('Mouse move at:', event.clientX, event.clientY);
});
这段代码会在鼠标在滑块元素上按下和移动时,打印出鼠标的位置。请注意,mousemove 事件会在鼠标在元素上移动时持续触发,即使鼠标按钮没有被按下。
如果你只想在鼠标按下并拖动滑块时才记录鼠标的移动,你可能需要添加一些额外的逻辑来跟踪鼠标的状态,例如:
var sliderElements = document.getElementsByClassName('passMod_slide-btn ');
var sliderElement = sliderElements[0];
var isMouseDown = false;
sliderElement.addEventListener('mousedown', function(event) {
console.log('Mouse down at:', event.clientX, event.clientY);
isMouseDown = true;
});
sliderElement.addEventListener('mousemove', function(event) {
if (isMouseDown) {
console.log('Mouse move at:', event.clientX, event.clientY);
}
});
sliderElement.addEventListener('mouseup', function(event) {
isMouseDown = false;
});
这段代码只有在鼠标按下并在滑块元素上移动时,才会打印出鼠标的位置。
8难点解释
z-index
解决元素遮盖的问题
在CSS中,元素的堆叠顺序(也就是哪个元素在上面,哪个元素在下面)是由多个因素决定的,包括元素的位置(position)、浮动(float)、层叠上下文(stacking context)、层叠等级(z-index)等。
在代码中,新创建的div元素的position属性被设置为absolute,这意味着这个元素会被放置在一个新的层叠上下文中。然而,如果页面中的其他元素也有自己的层叠上下文,并且它们的z-index值比新创建的div元素的z-index值大,那么这些元素就会覆盖在新创建的div元素上面。
因此可以通过给新创建的div元素添加一个较大的z-index值来解决这个问题。例如:
nDiv.style.cssText = "position:absolute; width:5px; height:5px; border-radius:50%; z-index:9999"
这样,无论页面中的其他元素的z-index值是多少,新创建的div元素总是会显示在最上面。
pointer-events
解决无法操作下方滑块元素的问题
可以使用CSS的pointer-events属性来确保新创建的div元素总是显示在最上层。pointer-events属性指定了元素如何响应鼠标事件。如果你将其设置为none,那么鼠标事件将会“穿透”这个元素,直接作用于下面的元素。这样,即使新创建的div元素在视觉上覆盖了其他元素,用户仍然可以与这些被覆盖的元素互动。
- 在CSS中,
pointer-events属性用于指定元素如何响应鼠标或触摸事件。当你将pointer-events设置为none时,元素将不再是鼠标事件的目标。也就是说,任何对该元素的点击或悬停操作都会“穿透”该元素,直接作用于其下面的元素。
这个属性在很多情况下都非常有用。例如,如果你有一个透明的元素覆盖在其他元素上面,你可以通过设置pointer-events: none来让用户可以与被覆盖的元素互动。或者,如果你有一个元素你不希望用户能够与其互动(例如,一个正在进行动画的元素),你也可以使用pointer-events: none。
两种方法区别
document.addEventListener("mousemove", function(event){
var x = event.pageX;
var y = event.pageY;
console.log("鼠标坐标为:" + x + ", " + y);
});
window.onmousemove = function(event) {
var x = event.pageX;
var y = event.pageY;
console.log("鼠标坐标为:" + x + ", " + y);
}
document.addEventListener("mousemove", function(event){...}) 和 window.onmousemove = function(event) {...} 都是用来监听鼠标移动事件的,但它们之间存在一些差异:
-
事件监听器的添加方式:
addEventListener方法允许你为同一事件添加多个监听器,而onmousemove属性只能设置一个监听器。如果你多次设置onmousemove,那么后面的设置会覆盖前面的设置。 - 更推荐的做法是使用
addEventListener方法来添加事件监听器,因为这种方法可以添加多个监听器到同一个事件。 -
事件的冒泡和捕获:
addEventListener方法允许你选择是否在捕获阶段处理事件,只需要将第三个参数设置为true即可。而onmousemove只在冒泡阶段处理事件。element.addEventListener('click', function(event) {
console.log('Clicked!');
}, true); -
监听的对象不同:
document和window是两个不同的对象,它们的范围和行为可能会有所不同。在大多数情况下,鼠标移动事件会冒泡到这两个对象,所以你可能不会注意到它们之间的差异。但在某些特殊情况下,比如当你的页面包含滚动条或者是在一个iframe中时,document和window可能会接收到不同的事件。
两种对象区别
window.addEventListener 和 document.addEventListener 都是用来在 JavaScript 中添加事件监听器的方法。它们的主要区别在于它们监听的对象不同:
window.addEventListener是在全局window对象上添加事件监听器。这意味着,无论事件在文档的哪个部分发生,只要它最终到达了window,就会触发该事件监听器。document.addEventListener是在document对象上添加事件监听器。由于document对象代表了 HTML 文档,因此,只有当事件在 HTML 文档内部发生并且冒泡到document时,才会触发该事件监听器。
至于哪个更推荐使用,这完全取决于你的具体需求。如果你希望在整个窗口范围内监听事件(包括滚动条、地址栏等),那么 window.addEventListener 可能是更好的选择。如果你只关心在 HTML 文档内部发生的事件,那么 document.addEventListener 可能更适合。在大多数情况下,两者可以互换使用,因为大多数事件都会从触发它的元素冒泡到 document,然后再冒泡到 window。但是,有些事件(如 load、unload 和 resize)只能在 window 上监听到。所以,你应该根据你的具体需求来选择使用哪个。
问题:无法监听到 mouseup 事件
应该可以通过监听
click事件来代替
在某些情况下,你可能无法在浏览器中监听到 mouseup 事件。这可能是由于以下原因:
- 事件冒泡被阻止:如果在事件处理程序中调用了
event.stopPropagation(),那么mouseup事件将不会冒泡到window或document。你需要检查是否有代码阻止了事件冒泡。 - 默认行为被阻止:如果在
mousedown事件处理程序中调用了event.preventDefault(),那么浏览器可能不会触发mouseup事件。你需要检查是否有代码阻止了默认行为。 - 事件监听器被移除:如果在
mousedown或mousemove事件处理程序中移除了mouseup事件监听器,那么你将无法监听到mouseup事件。 - 验证码防护机制:对于一些验证码(如百度的旋转滑块验证码),它们可能使用了一些防护机制来防止自动化操作。这可能包括阻止事件冒泡、阻止默认行为、移除事件监听器,或者使用其他的技术手段。
Part3通过坐标点绘制移动轨迹
var data = [
{
"t": 1700642911180,
"fx": 518,
"fy": 418
},
{
"t": 1700642911381,
"fx": 524,
"fy": 412
},
{
"t": 1700642911690,
"fx": 518,
"fy": 393
},
{
"t": 1700642911892,
"fx": 590,
"fy": 394
}
];
var canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.cssText = "position:absolute; top:0; left:0; z-index:9999; pointer-events:none";
document.body.appendChild(canvas);
var context = canvas.getContext('2d');
context.lineWidth = 2;
data.forEach(function(point, index) {
// 绘制红色线条
context.beginPath();
context.strokeStyle = 'red';
if (index !== 0) {
context.moveTo(data[index - 1].fx, data[index - 1].fy);
context.lineTo(point.fx, point.fy);
context.stroke();
}
// 绘制黄色圆点
context.beginPath();
// 这里的第3个参数可以修改圆的半径
context.arc(point.fx, point.fy, 4, 0, 2 * Math.PI, false);
context.fillStyle = 'black';
context.fill();
// 添加序号标签
context.beginPath();
// 如果你改变了字体大小,你也应该相应地改变 textHeight 的值,以确保文本仍然能够垂直居中显示
context.font = "6px Verdana";
context.fillStyle = "white";
var textWidth = context.measureText(index).width;
var textHeight = 6; // 这是字体大小的近似值
context.fillText(index, point.fx - textWidth / 2, point.fy + textHeight / 2);
});