JavaScript事件代理:寻找target目标元素、求结点深度

基础知识储备

本文的出彩之处在最后两部分,前面只是基础介绍。


JS中的事件代理,网上有很多大神已经介绍的非常完美了,这里无需我的赘述。在学习事件代理之前,最好把事件模型学习了,就是捕获阶段、目标阶段、冒泡阶段 那些事情。这里,我推荐两篇别人的文章:


一、JavaScript 事件模型 事件处理机制

二、浏览器事件模型中捕获阶段、目标阶段、冒泡阶段实例详解


事件代理

这里写图片描述


为什么要使用事件代理(事件委托)呢?


在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’。


这里写图片描述


怎么解决这个问题呢?


有了上面求元素结点深度的知识,我们就很容易操作了,下面直接上答案吧。


这里写图片描述


这里写图片描述


问题得以解决!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值