本文系统梳理JavaScript中的鼠标事件类型,包括点击、移动、经过及按键事件。重点解析在不同浏览器环境下获取鼠标坐标的兼容方案,通过对比pageX、clientX等属性解决定位难题,并提供拖放操作的算法逻辑与代码实现,帮助开发者掌握鼠标交互的核心技术。
在JavaScript开发中,鼠标事件是构建Web交互的核心机制之一。常见的鼠标点击相关事件涵盖四种:click(单击)、dblclick(双击)、mousedown(按下)以及mouseup(松开)。其中,click事件应用最为广泛;而mousedown与mouseup组合使用,则常用于实现鼠标拖放或元素拉伸等复杂交互功能。
一、鼠标事件类型详细说明
| 事件类型 | 说明 |
|---|---|
| click | 单击鼠标左键时发生,如果右键也按下则不会发生。当用户的焦点在按钮上并按了 Enter 键时,同样会触发这个事件 |
| dblclick | 双击鼠标左键时发生,如果右键也按下则不会发生 |
| mousedown | 单击任意一个鼠标按钮时发生 |
| mouseout | 鼠标指针位于某个元素上且将要移出元素的边界时发生 |
| mouseover | 鼠标指针移出某个元素到另一个元素上时发生 |
| mouseup | 松开任意一个鼠标按钮时发生 |
| mousemove | 鼠标在某个元素上时持续发生 |
二、鼠标点击
鼠标点击事件主要包含click(单击)、dblclick(双击)、mousedown(按下)和mouseup(松开)四种类型。在实际开发中,click事件使用频率最高;mousedown和mouseup则多用于实现拖放或拉伸功能。需要注意的是,若事件处理函数返回false,将阻止绑定对象的默认行为。
示例
在示例场景中,当超链接的href属性设置为自身(如设计阶段常用的“#”或“?”)时,可通过事件处理函数取消点击后的默认行为,从而避免页面刷新。
<a name="tag" id="tag" href="#" rel="external nofollow" >a</a>
<script>
var a = document.getElementsByTagName("a"); //获取页面中所有超链接元素
for (var i = 0; i < a.length; i ++) { //遍历所有a元素
if ((new RegExp(window.location.href)).test(a[i].href)) {
//如果当前超链接href属性中包含本页面的URL信息
a[i].onclick = function () { //则为超链接注册鼠标单击事件
return false; //将禁止超链接的默认行为
}
}
}
</script>
执行该示例代码后,点击超链接将不会触发页面跳转或刷新效果。
三、鼠标移动
mousemove事件属于实时响应类型。只要鼠标指针位置发生微小变化(至少移动一个像素),该事件即被触发。其响应灵敏度取决于鼠标移动速度及浏览器跟踪更新的频率。
示例
以下示例展示了如何综合运用多种鼠标事件来实现页面元素的拖放功能。实现该功能需解决几个关键问题。
- 首先,需将拖放元素设置为绝对定位,并设计相应的事件响应流程,这一步相对容易实现。
- 其次,需明确几个关键坐标概念:按下鼠标时的指针坐标、移动过程中的当前鼠标指针坐标、松开鼠标时的指针坐标、拖放元素的原始坐标以及拖动过程中的元素坐标。
- 算法设计方面:在按下鼠标时,获取被拖放元素及鼠标指针的初始位置;在移动过程中,实时计算鼠标偏移距离,并将该偏移量与被拖放元素的原始坐标相加,从而得出拖放元素的实时坐标。
如图所示,变量ox和oy分别记录按下鼠标时被拖放元素的纵横坐标值,可通过事件对象的offsetLeft和offsetTop属性获取。变量mx和my表示按下鼠标时鼠标指针的坐标位置。而event.mx和event.my是事件对象的自定义属性,用于存储鼠标移动时的实时位置。获取上述三对坐标值后,即可动态计算拖动中元素的实时坐标:x轴值为ox+event.mx-mx,y轴值为oy+event.my-my。当释放鼠标按钮时,可释放相关事件类型,并记录松开鼠标指针时拖动元素的坐标及鼠标位置,供下次拖放操作调用。

整个拖放操作的示例代码如下:
<div id="box" ></div>
<script>
// 初始化拖放对象
var box = document.getElementById("box");
// 获取页面中被拖放元素的引用指针
box.style.position = "absolute"; // 绝对定位
box.style.width = "160px"; // 定义宽度
box.style.height = "120px"; // 定义高度
box.style.backgroundColor = "red"; // 定义背景色
// 初始化变量,标准化事件对象
var mx, my, ox, oy; // 定义备用变量
function e(event){ // 定义事件对象标准化函数
if( ! event){ // 兼容IE浏览器
event = window.event;
event.target = event.srcElement;
event.layerX = event.offsetX;
event.layerY = event.offsetY;
}
event.mx = event.pageX || event.clientX + document.body.scrollLeft;
// 计算鼠标指针的x轴距离
event.my = event.pageY || event.clientY + document.body.scrollTop;
// 计算鼠标指针的y轴距离
return event; // 返回标准化的事件对象
}
// 定义鼠标事件处理函数
document.onmousedown = function(event){ // 按下鼠标时,初始化处理
event = e(event); // 获取标准事件对象
o = event.target; // 获取当前拖放的元素
ox = parseInt(o.offsetLeft); // 拖放元素的x轴坐标
oy = parseInt(o.offsetTop); // 拖放元素的y轴坐标
mx = event.mx; // 按下鼠标指针的x轴坐标
my = event.my; // 按下鼠标指针的y轴坐标
document.onmousemove = move; // 注册鼠标移动事件处理函数
document.onmouseup = stop; // 注册松开鼠标事件处理函数
}
function move(event){ // 鼠标移动处理函数
event = e(event);
o.style.left = ox + event.mx - mx + "px"; // 定义拖动元素的x轴距离
o.style.top = oy + event.my - my + "px"; // 定义拖动元素的y轴距离
}
function stop(event){ // 松开鼠标处理函数
event = e(event);
ox = parseInt(o.offsetLeft); // 记录拖放元素的x轴坐标
oy = parseInt(o.offsetTop); // 记录拖放元素的y轴坐标
mx = event.mx ; // 记录鼠标指针的x轴坐标
my = event.my ; // 记录鼠标指针的y轴坐标
o = document.onmousemove = document.onmouseup = null;
// 释放所有操作对象
}
</script>
四、鼠标经过
鼠标经过事件包含移过(mouseover)和移出(mouseout)两种类型。当鼠标指针移至某元素上时触发mouseover;移出该元素时触发mouseout。需注意,若从父元素移至子元素,也会触发父元素的mouseover事件。
示例
在以下示例中,为3个嵌套的div元素分别定义了mouseover和mouseout事件处理函数。此时,从外层父元素移动到内部子元素时,会触发父元素的mouseover事件,但不会触发mouseout事件。
<div>
<div>
<div>盒子</div>
</div>
</div>
<script>
var div = document.getElementsByTagName("div");
// 获取3个嵌套的div元素
for(var i=0;i<div.length;i++){ // 遍历嵌套的div元素
div[i].onmouseover = function(e){ // 注册移过事件处理函数
this.style.border = "solid blue";
}
div[i].onmouseout = function(){ // 注册移出事件处理函数
this.style.border = "solid red";
}
}
</script>五、鼠标来源
事件发生后,可通过事件对象的target属性获取触发事件的节点元素。若需在IE事件模型中实现相同功能,可使用srcElement属性。
示例1
在以下示例中,当鼠标移过页面中的div元素时,会弹出提示对话框,显示当前元素的标签名称。
<div>div元素</div>
<script>
var div = document.getElementsByTagName("div")[0];
div.onmouseover = function(e){ // 注册mouseover事件处理函数
var e = e || window.event; // 标准化事件对象,兼容DOM和IE事件模型
var o = e.target || e.srcElement; // 标准化事件属性,获取当前事件的节点
alert(o.tagName); // 返回字符串“DIV”
}
</script>
此外,DOM事件模型还定义了currentTarget属性。当事件在传播过程中(如捕获和冒泡阶段)时,该属性值可能与target不同。因此,在事件处理函数中,通常建议使用该属性而非this关键字来获取当前对象。除上述通用事件属性外,若需获取鼠标指针来源以移动元素,在DOM事件模型中可使用relatedTarget属性获取当前事件的相关节点;在IE事件模型中,可使用fromElement获取mouseover事件中鼠标移过的元素,使用toElement属性获取mouseout事件中鼠标移到的文档元素。
示例2
在以下示例中,当鼠标移到div元素上时,会弹出“BODY”字符提示,表明鼠标指针是从body元素移入的;移开鼠标时,同样弹出“BODY”提示,表明离开div元素后将移向body元素。
<div>div元素</div>
<script>
var div = document.getElementsByTagName("div")[0];
div.onmouseover = function(e){
var e = e || window.event;
var o = e.relatedTarget || e.fromElement; //标准化事件属性,获取与当前事件相关的节点
alert(o.tagName);
}
div.onmouseout = function(e){
var e = e || window.event;
var o = e.relatedTarget || e.toElement; // 标准化事件属性,获取与当前事件相关的节点
alert(o.tagName);
}
</script>
六、鼠标定位
获取事件发生时的鼠标位置至关重要。由于浏览器存在兼容性差异,各浏览器在事件对象中定义了不同的属性,具体如表所示。这些属性均以像素值定义鼠标坐标,但因参照坐标系不同,精确计算鼠标位置较为复杂。
属性及其兼容性
| 属性 | 说明 | 兼容性 |
|---|---|---|
| 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 |
示例1
下文介绍如何配合使用多种鼠标坐标属性,以实现兼容不同浏览器的鼠标定位方案。
首先分析screenX和screenY属性。这两个属性获得所有浏览器支持,理论上是最优选择,但其坐标系基于计算机屏幕(以屏幕左上角为原点)。对于以浏览器窗口为活动空间的网页而言,由于屏幕分辨率、窗口大小和位置各异,这使得在网页中定位鼠标变得困难。
其次,若以document对象为坐标系,可选用pageX和pageY属性在浏览器窗口内定位。这对设计鼠标跟随功能较为有利,因为跟随元素通常以绝对定位方式在窗口中移动,在mousemove事件处理函数中,将pageX和pageY值传递给绝对定位元素的top和left样式属性即可。
IE事件模型不支持上述属性,因此需寻求兼容IE的方法。clientX和clientY属性以window对象为坐标系,且IE模型支持,故可选用。但需考虑window对象可能存在的滚动条偏移量,因此还需加上相对于window对象的页面滚动偏移量。
var posX = 0, posY = 0;
var event = event || window.event;
if (event.pageX || event.pageY) {
posX = event.pageX;
posY = event.pageY;
} else if (event.clientX || event.clientY) {
posX = event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
posY = event.clientY + document.documentElement.scrollTop + document.body.scrollTop;
}
在上述代码中,首先检测pageX和pageY属性是否存在,若存在则获取其值;若不存在,则检测并获取clientX和clientY属性值,随后加上document.documentElement和document.body对象的scrollLeft和scrollTop属性值,从而在不同浏览器中获得一致的坐标值。
示例2
封装鼠标定位代码。设计思路:根据传递的具体对象及相对鼠标指针的偏移量,使该对象跟随鼠标移动。
首先定义一个封装函数,传入参数包括对象引用指针、相对鼠标指针的偏移距离以及事件对象。该函数根据事件对象获取鼠标坐标,并将对象设置为绝对定位,定位值为鼠标指针当前的坐标。
封装代码如下:
var pos = function (o, x, y, event) { //鼠标定位赋值函数
var posX = 0, posY = 0; //临时变量值
var e = event || window.event; //标准化事件对象
if (e.pageX || e.pageY) { //获取鼠标指针的当前坐标值
posX = e.pageX;
posY = e.pageY;
} else if (e.clientX || e.clientY) {
posX = event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
posY = event.clientY + document.documentElement.scrollTop + document.body.scrollTop;
}
o.style.position = "absolute"; //定义当前对象为绝对定位
o.style.top = (posY + y) + "px"; //用鼠标指针的y轴坐标和传入偏移值设置对象y轴坐标
o.style.left = (posX + x) + "px"; //用鼠标指针的x轴坐标和传入偏移值设置对象x轴坐标
}
以下测试封装代码。为document对象注册鼠标移动事件处理函数,并传入鼠标定位封装函数,传入的对象为div元素,设置其位置向鼠标指针右下方偏移(10,20)的距离。鉴于DOM事件模型通过参数形式传递事件对象,调用函数时务必传递事件对象。
<div id="div1">鼠标追随</div>
<script>
var div1 = document.getElementById("div1");
document.onmousemove = function (event) {
pos (div1, 10, 20, event);
}
</script>示例3
获取鼠标指针在元素内的坐标。使用offsetX和offsetY属性可实现此目标,但Mozilla浏览器不支持。可选用layerX和layerY属性来兼容Mozilla浏览器。
设计代码如下:
var event = event || window.event;
if (event.offsetX || event.offsetY) { //适用非Mozilla浏览器
x = event.offsetX;
y = event.offsetY;
} else if (event.layerX || event.layerY) { //兼容Mozilla浏览器
x = event.layerX;
y = event.layerY;
}然而,layerX和layerY属性以绝对定位的父元素为参照物,而非元素自身。若无绝对定位的父元素,则以document对象为参照。为此,可通过脚本动态添加或手动添加的方式,在元素外层包裹一个绝对定位的父元素,从而解决浏览器兼容问题。考虑到元素间距离造成的误差,可适当减去1个或几个像素的偏移量。
完整设计代码如下:
<input type="text" id="text" />
<span style="position:absolute;">
<div id="div1" style="width:200px;height:160px;border:solid 1px red;">鼠标跟随</div>
</span>
<script>
var t = document.getElementById("text");
var div1 = document.getElementById("div1");
div1.onmousemove = function (event) {
var event = event || window.event; //标准化事件对象
if (event.offsetX || event.offsetY) {
t.value = event.offsetX + "" + event.offsetY;
} else if (event.layerX || event.layerY) {
t.value = (event.layerX-1) + "" + (event.layerY-1);
}
}
</script>
该方法能解决在元素内部定位鼠标指针的问题。但由于在元素外包裹了绝对定位元素,可能破坏页面整体结构布局。在确保这种人为方式不会导致布局混乱的前提下,可考虑选用此方法。
七、鼠标按键
通过事件对象的button属性可获取当前按下的鼠标键,该属性适用于click、mousedown、mouseup事件类型。不同模型的约定如下表所示。
| 单击 | IE 事件模型 | DOM 事件模型 |
|---|---|---|
| 左键 | 1 | 0 |
| 右键 | 2 | 2 |
| 中键 | 4 | 1 |
IE事件模型支持位掩码技术,可侦测同时按下的多个键。例如,同时按下左右键,button属性值为1+2=3;同时按下中键和右键,值为2+4=6;同时按下左键和中键,值为1+4=5;同时按下3个键,值为1+2+4=7。
但DOM模型不支持这种掩码技术,若同时按下多个键,则无法准确侦测。例如,按下右键(2)与同时按下左键和右键(0+2=2)的值相同。因此,DOM模型的button属性约定存在较大缺陷。不过,实际开发中很少需要同时检测多个鼠标按钮,通常仅需探测左键或右键单击行为。
示例
以下代码可监测右键单击操作,并阻止默认行为发生。
document.onclick = function (e) {
var e = e || window.event; //标准化事件对象
if (e.button == 2) {
e.preventDefault();
return false;
}
}
当鼠标单击事件发生时,会触发一系列事件:mousedown、mouseup、click、dblclick。这些事件的响应顺序如下:
mousedown → mouseup → click → mousedown → mouseup → click → dblclick
当鼠标在对象间移动时,首先触发的事件是mouseout,即鼠标移出某对象时发生。接着,在这两个对象上都会触发mousemove事件。最后,在鼠标进入的对象上触发mouseover事件。
本文关于JavaScript鼠标事件类型及用法示例的介绍至此结束。如需了解更多JS鼠标事件相关内容,请搜索本站过往文章或继续浏览后续相关文章,感谢支持。