前端面试js-手写事件委托(一点小改进)

最近刚好在学js的事件机制,写这个是看到这篇文章提到了一个腾讯的面试题。我先把文章的代码稍作改动贴在这里。

<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本身。
因此我们修改代码为:

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'啦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值