从零开始学_JavaScript_系列(31)——事件代理/事件委托

来源:互联网 发布:手机变脸软件 编辑:程序博客网 时间:2024/06/04 19:52

(49)事件代理/事件委托

github:

https://github.com/qq20004604/some_demo/tree/master/%E4%BA%8B%E4%BB%B6%E4%BB%A3%E7%90%86


①简单来说,利用事件的捕获-触发-冒泡三阶段的机制,在冒泡阶段,父级(或更高级)结点处理触发事件,而非子节点(事件触发结点)触发事件。

 

从而避免给每个子节点绑定事件所带来的大量事件问题,(委托往往只需要一个即可)

 

完全不懂的可以参照链接:

http://www.cnblogs.com/owenChen/archive/2013/02/18/2915521.html

 

②如代码:

<!DOCTYPE HTML><html><head>    <meta charset="UTF-8">    <title>事件代理</title></head><body><ul id="test">    <li>a</li>    <li>b</li>    <li>c</li>    <li>d</li>    <li>        eeee        <span>ffff</span>        gg    </li></ul><script>    function setEvent() {        document.querySelector("#test").addEventListener("click", function (evt) {            console.log(evt);   //这个获取点击事件            console.log(evt.target);    //这个是获取触发点击事件的dom,是最底层的DOM(即事件目标)            console.log(evt.target.nodeName);   //显示HTML标签名            if (evt && evt.target.nodeName === 'LI') {                alert("文本内容为:" + evt.target.innerHTML + "的li结点被触发了");            }        })    }    setEvent();</script></body></html>

③优点:

【1】当dom结构单一时,可以省去大量的绑定事件的问题;

【2】当动态添加、删除子节点时(如上面的li),可以省去绑定、移除子节点的功夫,减少业务复杂度;

 

④缺点:

【1】DOM结构复杂时,很难满足需求,如上面最后一个li标签,点击span标签范围是不能触发事件的;(我觉得有办法处理,即跟踪其冒泡阶段,但是暂时不知道怎么写)

【2】如果父级DOM下,某些DOM有响应事件,某些DOM没有响应事件,那么需要进行额外的逻辑判断进行处理。

 

⑤在IE情形下,特别是兼容低版本IE时,不能简单的这么写。

参考链接:

http://www.w3cmark.com/2016/439.html

 

代码如下:

<!DOCTYPE HTML><html><head>    <meta charset="UTF-8">    <title>事件代理</title></head><body><ul id="test">    <li>a</li>    <li>b</li>    <li>c</li>    <li>d</li>    <li>        eeee        <span>ffff</span>        gg    </li></ul><script>    //参数依次为:委托元素,选择器(支持类、id和元素),事件类型,回调函数    function delegateEvent(parentElement, selector, eventType, fn) {        if (parentElement.addEventListener) {            //普通的,然后触发回调函数            parentElement.addEventListener(eventType, eventfn);        } else {            //兼容的处理,然后触发回调函数            parentElement.attachEvent("on" + eventType, eventfn);        }        function eventfn(e) {            //事件或者是兼容性处理的window的事件            console.log(e);            var e = e || window.event;            var target = e.target || e.srcElement;            if (matchSelector(target, selector)) {                if (fn) {                    //用call将目标dom作为this指向的对象                    fn.call(target, e);                }            }        }    }    /**     *  选择器匹配     *  不支持组合,只支持id、类、html标签名     */    function matchSelector(element, selector) {        // 匹配id        if (selector.charAt(0) === "#") {            return element.id === selector.slice(1);        }        // 匹配类名        if (selector.charAt(0) === ".") {            return (" " + element.className + " ").indexOf(" " + selector.slice(1) + " ") != -1;        }        // 匹配HTML标签名        return element.tagName.toLowerCase() === selector.toLowerCase();    }    //获取父节点    var parentNode = document.getElementById("test");    //调用事件委托函数,父节点作为代理结点,第二个参数是选择器,支持类名、标签名和id(但不能组合),第三个是事件,第四个参数是回调函数    delegateEvent(parentNode, "li", "click", function (e) {        console.log(e);        console.log(this);        alert("1");    })</script></body></html>


0 0