document.elementFromPoint
先說一下這個方法的參數
elemntFromPoint(x,y);//傳入坐標值,返回當前頁面上包含該坐標點的頂層元素注意2點,坐標值和頂層元素
先說坐標,因為不同的人理解是不一樣的,也就造就了這個方法在不同的瀏覽器中表現是不一樣的,所以在傳入坐標時就分 整體頁面坐標 和 可視區域坐標,我們看上篇文章中的圖來理解下:
中間的方塊是可視區域,紅點相對可視區域的左上角我們稱之為 clientX和clientY,相對于頁面起始處的左上角稱之為 pageX和pageY
有的瀏覽器在調用elementFromPoint時要求傳入clientX和clientY而有的要求pageX和pageY,具體的詳見:http://www.quirksmode.org/webkit.html 看 elementFromPoint部分,上面也提到如果在標準中進行規則統一,也會規定使用可視區域的坐標
顯然我們如果要用這個方法時,就要注意兼容了,而對于同一種瀏覽器,因為版本的不同,導致同樣的這個方法可能要求傳入的坐標也不同,比如chrome瀏覽器,那么,我們該如何去兼容呢?
The w3c specification says:
The elementFromPoint(x, y) method, when invoked, must return the element at coordinates x,y in the viewport. The element to be returned is determined through hit testing. If either argument is negative, x is greater than the viewport width excluding the size of a rendered scroll bar (if any), or y is greater than the viewport height excluding the size of a rendered scroll bar (if any), the method must return null. If there is no element at the given position the method must return the root element, if any, or null otherwise.
調用elementFromPoint時,必須傳入可視區域內的坐標,如果你傳入的坐標不在可視區域內,即使在這個坐標處有元素,也將返回null;我們可以根據這個特性來寫兼容代碼:
使用jq實現的代碼如下,我們可以很方便的改寫成自已的
(function($) {var check = false,isRelative = true;$.elementFromPoint = function(x, y) {if (!document.elementFromPoint) return null;if (!check) {var sl;if ((sl = $(document).scrollTop()) > 0) {isRelative = (document.elementFromPoint(0, sl + $(window).height() - 1) == null);} else if ((sl = $(document).scrollLeft()) > 0) {isRelative = (document.elementFromPoint(sl + $(window).width() - 1, 0) == null);}check = (sl > 0);}if (!isRelative) {x += $(document).scrollLeft();y += $(document).scrollTop();}return document.elementFromPoint(x, y);} })(jQuery);原理就是上面說的,如果頁面有滾動,則嘗試獲取頁面坐標最邊緣處的元素,如果能獲取到,說明是使用頁面坐標,因為在有滾動的情況下,獲取可視邊緣處的坐標,頁面坐標會大于可視區域的坐標,所以如果是用可視區域坐標,肯定返回null
嗯,一切看起來都還不錯,IE6 7就不行了,仔細看了下這個方法,這個方法最早應該是IE特有的,最后被其它瀏覽器實現,在IE下,一直使用的是可視區域的坐標,但是在IE6 7的情況下,當你傳大于可視區域的坐標時,也是可以獲取到值的,也就造成了上面兼容代碼無法在IE6 7下正常工作,所以上面的代碼并沒有考慮IE6 7的情況,需要你添加一些判斷。
除了坐標問題外,該方法只能返回頂層元素,也就是在有2個元素重疊的情況下,只能返回最上層的元素。
之前我也有寫過高效拖動的文章,比如拖動排序分類,常見的是鼠標在拖動的時候,不停的計算鼠標是在哪個分類上面,然后做出變換的效果,如果列表元素比較少的情況下還是可以的,如果大于1000個,而這些分類的高度不定,通過這個循環判斷的方法顯示就會覺得很卡
我在之前的文章中提到可以在mousemove時,不讓任何元素擋著鼠標(通常我們可能會在拖動時,讓被拖動的元素隨鼠標一起移動,這時候元素可能擋在鼠標的下方),可通過事件的event.target獲取鼠標指向的元素,這樣列表中有多少個元素都不會影響到效果
回頭說一下setCapture方法,該方法是IE下讓元素捕獲到事件,比如鼠標移到瀏覽器外邊也可以響應得到,然而這個方法在firefox在4版本時被引進firefox中,引入后如果拖動時你調用了setCapture,就算鼠標下面沒有東西擋著,event.target也始終是鼠標按下時的target,IE中則不是,調用setCapture后,mousemove時依然可以獲取到,當然IE下可能要用event.srcElement獲取
所以,保險起見,我們要調用setCapture,而調用后,firefox4以后又不能及時獲取到鼠標下的元素,拋開這些,在ios設備上,touchmouse時,同樣也是獲取不到手指指向的元素,所以只好回頭折騰這個elementFromPoint了。
在折騰這些的時候,還發現諸如getBoundingClientRect在ios設備上也是有問題的,這個方法正常返回相對可視區域的坐標,而在ios上,實現的卻是相對頁面的坐標,實在讓人郁悶
回頭再看一下兼容,之前做瀏覽器間的兼容,更多的是這個瀏覽器有這個方法,那個瀏覽器有那個方法,方法的不同而已,現在的兼容則是同樣的方法,最終的結果不同,比如setCapture還有getBoundingClientRect等,可能還有其它一些有問題的方法,這種兼容起來更麻煩,遠不如沒有方法來的干脆些。
總結
以上是生活随笔為你收集整理的document.elementFromPoint的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: leetcode 104. Maximu
- 下一篇: 电脑内部录音教程Virtual Audi