前端面試js-手寫事件委託(一點小改進)

最近恰好在學js的事件機制,寫這個是看到這篇文章提到了一個騰訊的面試題。我先把文章的代碼稍做改動貼在這裏。node

<body>
        <div id="outer" style="width:100%; height:200px; background-color: cornflowerblue;">
            <div style="width:200px; height: 150px; background-color: pink;" id='middle'>
                <div style="width:100px; height: 100px; background-color: yellowgreen;" id="inner"></div>
            </div>
        </div>
        <script>
            function delegateEvent(interfaceEle, selector, type, fn) {
                if(interfaceEle.addEventListener) {
                    interfaceEle.addEventListener(type, eventfn, false);
                } else {
                    interfaceEle.attachEvent("on" + type, eventfn);
                }

                function eventfn(e) {
                    var e = e || window.event;
                    var target = e.target || e.srcElement;
                    if(matchSelector(target, selector)) {
                        if(fn) {
                            fn.call(target, e);
                        }
                    }
                }
            }

            function matchSelector(ele, selector) {
                // if use id
                if(selector.charAt(0) === "#") {
                    return ele.id === selector.slice(1);
                }
                // if use class
                if(selector.charAt(0) === ".") {
                    return(" " + ele.className + " ").indexOf(" " + selector.slice(1) + " ") != -1;
                }
                // if use tagName
                return ele.tagName.toLowerCase() === selector.toLowerCase();
            }
            //調用
            var outer = document.getElementById("outer");
            var middle = document.getElementById("middle");
            delegateEvent(outer, "#middle", "click", function() {
                console.log('test');
            })
        </script>
    </body>

做者:一隻dororo
連接:https://www.jianshu.com/p/7ea01a3beb7a
來源:簡書
簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。

顯示效果如圖:
圖片描述面試

可是這段代碼有一個小問題:用鼠標點擊綠色方塊,不會輸出‘test’,這彷彿違背了咱們但願事件冒泡的初衷。
這是因爲在綁定的時候,很關鍵的一個地方在eventfn函數,它限制了只有當target就是selector匹配的元素時,纔會調用handler。
而事實上咱們在調用這個函數的時候,target是selector匹配到的元素的子節點也能夠。
在這裏介紹一個新的api,parent.contains(node),他返回一個布爾值,判斷node是否是parent節點的後代或parent自己。
所以咱們修改代碼爲:api

function delegateEvent(interfaceEle, selector, type, fn) {
    if(interfaceEle.addEventListener) {
        interfaceEle.addEventListener(type, eventfn, false);
    } else {
        interfaceEle.attachEvent("on" + type, eventfn);
    }

    function eventfn(e) {
        var $selector = document.querySelector(selector);
        var e = e || window.event;
        var target = e.target || e.srcElement;
        if(contain($selector, target)) {
            if(fn) {
                fn.call(target, e);
            }
        }
    }
}

function contain(parent, node) {
    if (parent.contains) {
        return parent.contains(node)
    } else { //兼容不支持contains方法的瀏覽器
        while (node) {
            if (node === parentNode) {
                return true;
            } else {
                node = node.parentNode;
            }
        }
        return false;
    }    
}

如今再點擊綠色方塊也能夠打印'test'啦。瀏覽器

相關文章
相關標籤/搜索