鱼C论坛

 找回密码
 立即注册
查看: 2457|回复: 10

[庖丁解牛] 0 2 3 6 ★ 原生JavaScript的事件委托

[复制链接]
发表于 2019-1-4 16:23:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 不二如是 于 2019-1-11 17:32 编辑




                               
登录/注册后可看大图


很多鱼油关于JS的问题会涉及到事件委托,在0 2 3 2 ★ JS执行机制大作战 中也涉及到了。

还是有必要仔细围绕这个东东,好好说一下。

事件委托的定义:
利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。


何为事件冒泡(event bubbling)呢?

这个概念是有微软提出滴,事件冒泡可以形象地比喻为:
游客,如果您要查看本帖隐藏内容请回复


giphy.gif


也就是说:
事件会从最内层的元素开始发生,一直向上传播,直到document对象。


因此在事件冒泡的概念下在 p 元素上发生 click 事件的顺序应该是:
p -> div -> body -> html -> document

大概了解到这一层面就够了,有机会关于“事件捕获和冒泡”,好好讲一下~

继续回到事件委托,在 js 中添加到页面上的事件处理程序的个数直接影响到网页的运行性能。

因为每个事件处理函数都是一个对象,是对象就会占用内存,而内存中对象越多,导致的结果就是性能越差。

而访问 dom 的次数越多,就会引起结构的重绘或者重排的次数也随之增多,会延迟整个页面的交互就绪时间。

这样对于在页面进行处理过后新增的 dom 元素,运用事件委托可以为新增的dom元素一并增减事件处理程序。

理论就是上面这样啦,进入敲代码环节。

我们实现一个p元素单击时,背景变绿的交互,创建基本代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件委托</title>
</head>
<body>
<div id="nodes">
    <P class="node_p">第一个p</P>
    <P class="node_p">第二个p</P>
    <P class="node_p">第三个p</P>
    <div id="childDiv">
        <p>这是子集菜单</p>
        <div>我是子集的div
            <p>我是子集的p</p>
        </div>
    </div>
</div>
<button>单击新增一个p元素</button>
</body>
</html>

接下来实现 JS 代码部分,我们先不要用事件委托,实现:
获取页面中所有的 p 元素然后用 for 循环遍历给每一个元素增加事件处理函数


创建JS:
<script>
    var nodes = document.getElementById("nodes");
    var ps = document.getElementsByTagName("p");
    console.log(ps);
    var btn = document.getElementsByTagName("button")[0];
    var inner = 33;
    btn.onclick = function() {
        inner++;
        var p = document.createElement("p");
        p.innerHTML = inner + "新增的p标签啊";
        nodes.appendChild(p);
        console.log(ps);
    };
    for (var i= 0;i<ps.length;i++){
        ps[i].onclick= function(){
            this.style.background = 'green'
        }
    }
</script>
Jan-11-2019 16-07-57.gif


然后单击p元素会看到:
Jan-11-2019 16-12-33.gif


原来存在的 p 元素单击后背景色正确变绿了,而新增加的p元素没有成功!

怎么肥四?

可以理解为浏览器的一种优化,如果每一个未经授权的新增元素获得所有现存的方法岂不乱套?

需要为新增的元素增加一个事件处理函数。

新增一个 myAddEvent() :
 var nodes = document.getElementById("nodes");
    var ps = document.getElementsByTagName("p");
    console.log(ps);
    var btn = document.getElementsByTagName("button")[0];
    var inner = 33;
    btn.onclick = function() {
        inner++;
        var p = document.createElement("p");
        p.innerHTML = inner + "新增的p标签啊";
        nodes.appendChild(p);
        // 将新dom元素增加到页面后在执行
        myAddEvent();
        console.log(ps);
    };

    // 增加事件处理函数,包裹for循环
    function myAddEvent(){
        for (var i= 0;i<ps.length;i++){
        ps[i].onclick= function(){
            this.style.background = 'green'
        }
    }
    }
Jan-11-2019 16-55-25.gif


搞定啦!

这时候虽然解决了为新增dom元素增加事件处理函数的问题,但是仔细考虑挥会发现:
性能却是比之前都有所下降。


究其原因就是又增加了一个事件处理函数(对象),又一次占用了内存。

所以,这个时候就会用到事件委托,这时候事件委托的优势也有所体现出来:
 var nodes = document.getElementById("nodes");
    var ps = document.getElementsByTagName("p");
    console.log(ps);
    var btn = document.getElementsByTagName("button")[0];
    var inner = 33;
    btn.onclick = function() {
        inner++;
        var p = document.createElement("p");
        p.innerHTML = inner + "新增的p标签啊";
        nodes.appendChild(p);
        console.log(ps);
    };

    // 事件委托
    nodes.onclick = function(e){
        var ev = e || window.event;
        var target = ev.target;
        //这里要判被处理元素节点的名字
        if(target.nodeName.toLowerCase() == 'p'){
            target.style.background = 'green'
        }
    }
Jan-11-2019 17-05-32.gif


通过 if 我们判被处理元素节点的名字。

也可以增加相应的判断条件:
 target.nodeName.toLowerCase() == 'p'||target.nodeName.toLowerCase() == 'span'

但是要注意不要使用父级元素的名称,因为再点击子元素之间的空气的时候,由于事件冒泡他会给父级元素也增加相应的事件处理函数。

因为返回的节点名称一般都是大写,所以这时要用 toLowerCase() 处理一下。


                               
登录/注册后可看大图








如果喜欢,别忘了评分


                               
登录/注册后可看大图


这位鱼油,如果喜欢本系列Js帖子,请订阅 专辑&#9758;传送门)(不喜欢更要订阅

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-11 11:11:39 | 显示全部楼层
终于更新了

点评

我很赞同!: 5.0
我很赞同!: 5
  发表于 2019-1-11 15:56

评分

参与人数 1鱼币 +6 收起 理由
不二如是 + 6 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-10 20:12:10 | 显示全部楼层
谢谢楼主
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-11-5 23:07:15 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-5-11 14:33:24 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-11-21 14:48:57 | 显示全部楼层
kk
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-6-13 11:06:18 | 显示全部楼层
。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-9-26 08:57:01 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-1-21 14:57:18 | 显示全部楼层
1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-10-14 14:23:05 | 显示全部楼层
1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 20:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表