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不是同一个东西

js事件委托

原文:https://www.cnblogs.com/xi-li/p/14735617.html

上一篇:小程序开发初体验,从静态demo到接入Bmob数据库完全实现


下一篇:在Raspberry Pi上运行Node-RED