在 JavaScript 中,當事件發生時,獲取滑鼠的位置是件很重要的事件。由於瀏覽器的不相容性,不同瀏覽器分別在各自事件物件中定義了不同的屬性,說明如下表所示。這些屬性都是以畫素值定義了滑鼠指標的坐標,但是由於它們參照的坐標系不同,導致精確計算滑鼠的位置比較麻煩。
屬性及其相容性
屬性 |
說明 |
相容性 |
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>
這種做法能夠解決在元素內部定位滑鼠指標的問題。但是,由於在元素外面包裹了一個絕對定位的元素,會破壞整個頁面的結構布局。在確保這種人為方式不會導致結構布局混亂的前提下,可以考慮選用這種方法。