zoukankan      html  css  js  c++  java
  • js事件委托

    JS里的事件委托:就是当事件触发时,把要做的事委托给父元素来处理。

    再通俗点:就是自己的事不想干,叫它爸爸,甚至爷爷、甚至祖先来干。

    作用:

    作用1:节约内存

    作用2:能为之后新增的DOM元素依然添加事件(如:js动态添加li)

    应用场景:

    场景1:当多个li标签需要添加点击事件时

    场景2: 新增元素没有绑定事件的问题(界面上有一个ul里面默认有5个li,并且还有一个按钮,当点击按钮就创建一个新的li,需要不管是默认有的li还是新的li都有点击事件)

    //场景1示例
    <html> <head> <meta charset="UTF-8"> <title>demo</title> </head> <body> <ul> <li>item1</li> <li>item2</li> <li>item3</li> <li>item4</li> <li>item5</li> </ul> <script type="text/javascript"> // 找到所有的li var liList = document.getElementsByTagName('li'); // 遍历所有的li,并给每个li添加点击事件 for (var i=0;i<liList.length;i++){ liList[i].onclick = function () { alert(this.innerHTML); } } </script> </body> </html>

    代码解析给5个li标签加了点击事件,当界面上点击li时,会打印它们各自li标签显示的内容。

    出现的问题:此时5个li,看起来每个li的点击事件触发时调用的都是同一个函数,即:

    function () {
        alert(this.innerHTML);
    } 

    但其实并不是这样。每个li绑定的都是一个全新的函数,只不过每个函数的样子都一模一样。

    如何验证这个结论呢?很简单,判断每个li标签的onclick是否相等就可以了。

    代码验证如下:

    alert(liList[0].onclick==liList[1].onclick);
    //弹出false

    至于上面说的函数长得一样,但不是同一个数据这种情况就类似于 var obj1 = {name:"jack",age:16}和var obj2 = {name:"jack",age:16},obj1 == obj2 得到的结果也会是false。

    至此,我们可以得到结论,如果有5个li,那么就有5个函数会被创建在内存中占据空间,那如果有100个li呢?就会有100个长相一模一样的函数在内存中常驻,对内存的开销是巨大的!
     
    解决办法利用事件冒泡的原理,把事件加在父元素(ul)身上!

    代码如下:

    var ul = document.getElementsByTagName('ul')[0];
        // 只用给ul加点击事件即可
        ul.onclick = function (e) {
    //事件对象在ie8中要通过window.event才能取到,因此e = e || window.event是做兼容处理 e
    = e || window.event; // e.target指的是被点击的那个li alert(e.target.innerHTML); }

    原理解析:

    回顾事件冒泡

    事件冒泡:即一个元素的事件触发后,会依次一级一级往上调用父级元素的同名事件,直到window(注:IE8和之前的浏览器只到document)

    例:div > p > span 当div和p以及span都添加了click事件,当点击span时,会依次向上触发span、p、div的click事件。其中,在每个触发的事件里,通过事件对象.target能拿到触发事件的源头元素,也就是 事件源alert(e.target),结果都是[object HTMLSpanElement].

    在回顾完事件冒泡后,我们显而易见得到结论:给所有li添加点击事件,只要加到它们的父元素ul身上的根本原因是利用了事件冒泡。也即:无论点击哪个li,都会自动触发ul的点击事件,然后在ul里通过e.target能获得真正被点击的那个li,继而拿到它的innerHTML

     小结:如果给一堆元素加事件,并且事件触发时执行的代码都差不多时,就可以把事件加在父元素身上啦!

    看,这样的形式是不是就相当于把自己的事件,委托在父元素身上处理了呢?因而它才会叫事件委托!

    思考:如果ul里还有其他子元素例如span,可我只想给li加点击事件,用原来写的事件委托还行吗?

    答案是否定的,因为根据事件冒泡原理,所有子元素点击后都会触发父元素的点击,因此,如果你点击了span,也会调用ul的点击事件,这就相当于给span也加了点击事件。这时候该怎么解决呢?

    很简单,只要判断一下事件源是不是li就行了,如果是li才执行代码,否则不执行,代码如下:

    <html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
    <ul>
        <li>item1</li>
        <li>item2</li>
        <li>item3</li>
        <li>item4</li>
        <li>item5</li>
        <span>我是span</span>
    </ul>
    <script type="text/javascript">
        var ul = document.getElementsByTagName('ul')[0];
        // 只用给ul加点击事件即可
        ul.onclick = function (e) {
            e = e || window.event;
            // 判断事件源是不是li
            if(e.target.nodeName.toLowerCase()=='li'){
                // e.target指的是被点击的那个li
                alert(e.target.innerHTML);
            }
        }
    </script>
    </body>
    </html>
    

    jQuery事件委托语法:

     $('父元素').on('事件名','哪个子元素触发',传给回调函数的参数,事件触发时的回调函数);

    解释:

    参数1:事件名,代表要绑定什么事件,但是记得不用加on,也就是说如果你想加点击事件,只要写'click'即可,注意是字符串!所以要打单引号或者双引号

    参数2:只能由哪个子元素触发,例如我写 "li",就代表只能由这个父元素里面的li触发事件,其他子元素不会触发。需要注意的是,这也是字符串,并且,参数2可以不写,那就代表仅仅只是给父元素加一个点击事件,并且所有子元素都能触发到这个事件(因为事件冒泡)

    参数3:其实一般不会用,就是如果想事件触发时,自己给回调函数传一些值就写,这个参数也可以不写!

    参数4:事件触发时的回调函数

    总结:参数1和参数4是必须的,其他是可选的,如果你要用事件委托,请写上参数2

    $('ul').on('click','li','我是数据',function (e) {
            console.log(e.data);
            console.log(e.target.innerHTML);
            // 或者
            console.log(this.innerHTML);
        })

    说明:

    1.on这个方法的参数3可以通过回调函数里的e.data拿到(但一般不会用,大家了解一下有这么个东西即可)

    2.在jQuery事件委托的回调函数里thise.target是同一个东西,但是在JSthise.target不是同一个东西

  • 相关阅读:
    HDU1258 Sum It Up(DFS)
    hdu 1078 FatMouse and Cheese(记忆化搜索)
    HDU1072 Nightmare (bfs+贪心)
    HDU 2102 A计划 经典搜索
    hdu 1180诡异的楼梯(bfs)
    HDU 1065.I Think I Need a Houseboat
    559_N叉树的最大深度
    236_二叉树的最近公共祖先
    589_N叉树的前序遍历
    每天进步一点点
  • 原文地址:https://www.cnblogs.com/xi-li/p/14735617.html
Copyright © 2011-2022 走看看