鼠標事件都是在特定位置發生的,我們可以通過event事件對象的各種屬性來獲得事件發生的坐標位置,有相對於視口的,有相對於整個文檔的,同樣頁面元素的位置也有相對視口的,也有滾動后的,這些都比較容易混淆,所以整理在這里,備忘,待查。
1.客戶區坐標位置(clientX/clientY)
我們可以通過event事件對象的clientX/clientY屬性獲得事件發生時鼠標指針在視口中的水平和垂直坐標。
示意圖:

2.屏幕坐標位置(screenX/scrennY)
通過event事件對象的screenX/screenY屬性,可以獲取鼠標事件發生時鼠標光標相對於整個電腦屏幕的坐標信息。
示意圖:

clientX/clientY和screenX/screenY區別demo:clientX/clientY和screenX/screenY區別demo
demo 源代碼戳這里:https://github.com/demo.html
3.頁面坐標位置(pageX/pageY)
通過事件對象的pageX/pageY屬性可以獲得鼠標事件發生時鼠標光標相對於整個文檔元素的坐標位置(包含滾動)。
在頁面沒有滾動的情況下,通常pageX/pageY的值與clientX/clientY的值相等。
4.layerX/layerY
事件對象還有個不那么常見的屬性,那就是layerX/layerY,他是對於絕對定位元素來說的,相對於當前點擊元素的左上角定位的。當頁面上的元素時相對定位(position:relative)的時候,通常pageX/pageY和layerX/layerY的值是相同的,但是當元素絕對定位(position:absolute)了的時候,layerX/layerY就將鼠標光標位置相對於本身的左上角定位了。
下面demo有助於理解,猛戳:
pageX\pageY & layerX\layerY示意demo:pageX\pageY & layerX\layerY
demo代碼猛戳這里:https://github.com/pageXandLayerX.html
5.偏移量:(offsetWidth/offsetHeight/offsetLeft/offsetTop)
元素的偏移量(offsetLeft/offsetTop)是相對於它的直接父元素來說的。
[元素的可見大小由其高度和寬度決定,這包括所有的內邊距(padding)、滾動條和邊框(border)大小(注意這里面不包括margin喔,因為margin是透明的,一般使用它控制元素之間的間隔)。這是為什么呢,因為吧,可以一試,如果我們給元素添加背景的話,那么背景會被應用 於由內容和內邊距組成的區域,而添加邊框(border)會在內邊距(padding)的區域外邊加一條線,margin透明,當然不在可見范圍內啦。]
示意圖:

Tips:
1.如果要想知道某個元素在頁面上的偏移量,將這個元素的offsetLeft和offsetTop與其offsetParent的相同屬性相加,如此循環至根元素,就可以得到一個基本准確的值。
2.如果有些div他的offsetParent是<body>的話,那么也可以嘗試getElementLeft()和getElementTop()方法,不出意外地話會返回跟offsetLeft和offsetTop相同的值。
3.所有這些偏移量都是只讀的,而且每次訪問的時候都需要重新計算,要注意性能問題。
6.客戶區的大小(clientWidth/clientHeight)
元素的客戶區的大小就是指元素內容及其內邊距所占空間的大小(滾動條占用的空間不計算在內)。(clientWidth=width+padding(left、right);clientHeight=height+padding(top、bottom))
clientWidth與offsetWidth區別示例:clientWidth與offsetWidth區別
7.滾動大小(scrollWidth/scrollHeight/scrollLeft/scrollTop)
有些元素,即使沒有執行任何代碼也會自動的添加滾動條,如<html>,但是另外一些元素,則需要通過css的overflow屬性進行設置才能滾動。
通常認為<html>元素是在web瀏覽器的視口中滾動的元素(ie6之前版本運行在混雜模式下是<body>元素,這也是上面計算視口大小代碼if,else的原因),因此帶有垂直滾動條的頁面總高度就是document.documentElement.scrollHeight。

當overflow屬性設置為 auto時,內容可以超過元素的尺寸,並顯示滾動條。這時就可以使用scrollwidth屬性來檢索內容的寬度范圍內的元素。
MSDN上找到了相關的例子:scrollWidth屬性示例
更具體的信息,可以查看這里:MSDN scrollWidth
Tips:
在確定文檔的總高度時,必須取得scrollWidth、clientWidth和scrollHeight、clientHeight中的最大值,這樣才能保證在跨瀏覽器的情況下取得較為准確的結果。
8.window.scrollX/window.scrollY與window.pageXOffset/window.pageYOffset
window.scrollX/window.scrollY返回的是整個文檔document在水平和豎直方向滾動了的距離。
window.pageXOffset/window.pageYOffset相當於window.scrollX/window.scrollY的別名一樣的。也就是說:
window.pageXOffset == window.scrollX; // 總是返回真
但在跨瀏覽器的情況下,盡量使用window.pageXOffset/window.pageYOffset比較好。
所以為了保險起見,使用下面這樣的代碼來判斷文檔在垂直和水平防線滾動的距離比較好:
var x = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft; var y = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
9.window.innerHeight/window.innerWidth
window.innerHeight/window.innerWidth記錄了視口內文檔元素的實際高度和寬度,實際上還有window.outerHeight/window.outerWidth。
下圖可以很好地區分兩者:

另外,如果頁面滾動了也不會影響他的innerHeight和innerWidth值:


此外,如果頁面中有frameset時:
var intFrameHeight = window.innerHeight; // or var intFrameHeight = self.innerHeight; // will return the height of the frame viewport within the frameset var intFramesetHeight = parent.innerHeight; // will return the height of the viewport of the closest frameset var intOuterFramesetHeight = top.innerHeight; // will return the height of the viewport of the outermost frameset
10.getBoundingClientRect()方法
getBoundingClientRect用於獲得頁面中某個元素的左,上,右和下分別相對瀏覽器視窗的位置。getBoundingClientRect是DOM元素到瀏覽器可視范圍的距離(不包含文檔卷起的部分)。該函數返回一個Object對象,該對象有6個屬性:top,lef,right,bottom,width,height;這里的top、left和css中的理解很相似,width、height是元素自身的寬高,但是right,bottom和css中的理解有點不一樣。right是指元素右邊界距窗口最左邊的距離,bottom是指元素下邊界距窗口最上面的距離。
通過這個方法可以比較方便的獲取頁面元素的位置:
var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;
var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;
關於這個方法MSDN上有詳細的解釋:getBoundingClientRect()方法
總結:
上面那些屬性都是很容易搞混的。而且也要注意不同的瀏覽器中可能存在的差別,使用的時候測試一下就能更准確的應用了。
搞清楚了上面這些相關屬性和方法,應該就能理解小胡子寫給我的這個demo了: js原生拖放
源代碼在這里:https://github.com/dragdemo.html
整理這篇文章的契機,就是我在實現原生的拖放功能。
備忘,待查。
