document.elementFromPoint

先說一下這個方法的參數css

elemntFromPoint(x,y);//傳入座標值,返回當前頁面上包含該座標點的頂層元素

注意2點,座標值和頂層元素html

先說座標,由於不一樣的人理解是不同的,也就造就了這個方法在不一樣的瀏覽器中表現是不同的,因此在傳入座標時就分 總體頁面座標 和 可視區域座標,咱們看上篇文章中的圖來理解下:
pic
中間的方塊是可視區域,紅點相對可視區域的左上角咱們稱之爲 clientX和clientY,相對於頁面起始處的左上角稱之爲 pageX和pageYios

有的瀏覽器在調用elementFromPoint時要求傳入clientX和clientY而有的要求pageX和pageY,具體的詳見:http://www.quirksmode.org/webkit.html 看 elementFromPoint部分,上面也提到若是在標準中進行規則統一,也會規定使用可視區域的座標web

顯然咱們若是要用這個方法時,就要注意兼容了,而對於同一種瀏覽器,由於版本的不一樣,致使一樣的這個方法可能要求傳入的座標也不一樣,好比chrome瀏覽器,那麼,咱們該如何去兼容呢?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.dom

調用elementFromPoint時,必須傳入可視區域內的座標,若是你傳入的座標不在可視區域內,即便在這個座標處有元素,也將返回null;咱們能夠根據這個特性來寫兼容代碼:ui

使用jq實現的代碼以下,咱們能夠很方便的改寫成自已的spa

(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);

原理就是上面說的,若是頁面有滾動,則嘗試獲取頁面座標最邊緣處的元素,若是能獲取到,說明是使用頁面座標,由於在有滾動的狀況下,獲取可視邊緣處的座標,頁面座標會大於可視區域的座標,因此若是是用可視區域座標,確定返回nullfirefox

嗯,一切看起來都還不錯,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等,可能還有其它一些有問題的方法,這種兼容起來更麻煩,遠不如沒有方法來的乾脆些。

相關文章
相關標籤/搜索