1. 程式人生 > >JavaScript事件代理:尋找target目標元素、求結點深度

JavaScript事件代理:尋找target目標元素、求結點深度

基礎知識儲備

本文的出彩之處在最後兩部分,前面只是基礎介紹。

JS中的事件代理,網上有很多大神已經介紹的非常完美了,這裡無需我的贅述。在學習事件代理之前,最好把事件模型學習了,就是捕獲階段、目標階段、冒泡階段 那些事情。這裡,我推薦兩篇別人的文章:

事件代理

這裡寫圖片描述

為什麼要使用事件代理(事件委託)呢?

在JavaScript中,新增到頁面上的事件處理程式數量將直接關係到頁面的整體執行效能,因為需要不斷的與DOM節點進行互動,訪問DOM的次數越多,引起瀏覽器重繪與重排的次數也就越多,就會延長整個頁面的互動就緒時間,這就是為什麼效能優化的主要思想之一就是減少DOM操作的原因;如果要用事件委託,就會將所有的操作放到JS程式裡面,與DOM的操作就只需要互動一次,這樣就能大大的減少與DOM的互動次數,提高效能;

每個函式都是一個物件,是物件就會佔用記憶體,物件越多,記憶體佔用率就越大,自然效能就越差了,記憶體可是個很寶貴的東西,比如下面的5個div,就要佔用5個記憶體空間,如果是成千上萬個呢?效能低劣可想而知,如果用事件代理,那麼我們就可以只對它的父級(如果只有一個父級)這一個物件進行操作,這樣我們就需要一個記憶體空間就夠了,自然效能就會更好。

<html>
    <head>
        <meta charset="utf-8">
        <style type="text/css">
            #mySection
>div { height: 30px; border: 1px solid orange; margin-top: 2px; }
</style> </head> <body> <section id="mySection"> <div>guoyu-------------1</div> <div>
guoyu-------------2</div> <div>guoyu-------------3</div> <div>guoyu-------------4</div> <div>guoyu-------------5</div> </section> <script type="text/javascript"> var mySection = document.getElementById('mySection'); mySection.onclick = function(ev) { var oEvent = ev || event; var target = oEvent.target || oEvent.srcElement; if (target.nodeName.toLowerCase() === 'div') { console.info(target.innerText); } }; </script> </body> </html>

這裡寫圖片描述

求一個元素結點的深度

document>html>body>div>ul>li
上面,li 元素相對與document元素的深度就是6,也就是從document元素算起,li 是第6代了。
怎麼求呢?其實很簡單,一般我們做迴圈習慣性用for語句,對於不知道要迴圈多少次的迴圈,我們一般用while迴圈。這樣做只是為了可讀性,其實未知迴圈次數也可以用for,但可讀性略差。

function nodeDepth(ele) {
    var depth = 0;
    while(ele) {
        console.log(ele);
        ele = ele.parentNode;
        depth++;

    }
    return depth;
}


function nodeDepth1(ele) {
    var depth = 0;
    for (;ele;ele=ele.parentNode) {
        console.log(ele);
        depth++;
    }
    return depth;
}

我們看個例項吧:

<html>
    <head>
        <meta charset="utf-8">
        <style type="text/css">
            * {padding: 0;margin: 0;}
            #mySection {
                height: 30px;
                background: orange;
            }
        </style>
    </head>
    <body>
        <section id="mySection"></section>

        <script type="text/javascript">
            var mySection = document.getElementById('mySection');
            function nodeDepth(ele) {
                var depth = 0;
                while(ele) {
                    console.log(ele);
                    ele = ele.parentNode;
                    depth++;    
                }
                return depth;
            }

            function nodeDepth1(ele) {
                var depth = 0;
                for (;ele;ele=ele.parentNode) {
                    console.log(ele);
                    depth++;
                }
                return depth;
            }
            console.log(nodeDepth(mySection));
            console.log('-------------------------------');
            console.log(nodeDepth1(mySection));
    </script>

    </body>
</html>

這裡寫圖片描述

尋找事件目標

target到底是指哪個元素?

其實,event.target指的是滑鼠點選的那一點所在的一個元素,那麼,點選所在點涉及到好幾層元素,到底是哪個元素,是深度最深的那個元素,也就是“輩分”最小的那個元素,比如,有如下層級:section>div>ul>li,如果滑鼠點到 li 的“地盤”了,那麼target指的就是li,儘管也是它前輩們的地盤,但target並不是ul、不是div、不是section。上面為了說明事件代理,所以舉了一個最簡單的例子。

然而,事實上往往沒有這麼簡單,我們需要處理的目標元素很可能並不是深度最深的那個元素,而是最深元素的某個前輩結點,而且最深的元素還把這個前輩元素100%的填充了,也就是完全“遮擋”住了,如此以來,上面的程式碼就有問題了,有什麼問題呢?

這裡寫圖片描述

第一個div被子元素p滿滿的填充了,target已經不再是div了,而是子元素p,所以執行結果如下,無論怎麼點選黃色區域,也打印不出來’guoyu————-1’。

這裡寫圖片描述

怎麼解決這個問題呢?

有了上面求元素結點深度的知識,我們就很容易操作了,下面直接上答案吧。

這裡寫圖片描述

這裡寫圖片描述

問題得以解決!