JavaScript事件

总结笔记,关于JavaScript事件。

1、js事件流

在这里插入图片描述
上图为js事件流的全过程,从图中可以得知:
一个完整的事件流是从window开始,最后回到window的一个过程。
事件流分为三个阶段,1-5是捕获阶段,5-6是目标阶段,6-10是冒泡阶段。

2、addEventListener的第三个参数

element.addEventListener(event, function, useCapture);
我们平常用的addEventListener方法中,一般只会用到前两个参数,第一个是需要绑定的事件,第二个是触发事件后要执行的函数。第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数,如果将其设置为true,则表示在事件捕获阶段调用事件处理函数。

<!DOCTYPE html>
<html>
<head>
    <title>事件委托</title>
    <style>
        body,html{
            margin:0px;
            padding:0px;
        }
        #parent{
            width: 300px;
            height: 300px;
            background-color: #808080;   
            display:flex;
            align-items:center;
            justify-content:center;
            margin:100px;
        }
        #child {
            width: 200px;
            height: 200px;
            background-color: #999;
        }

    </style>
</head>
<body>
    <div id="parent">
        <div id="child">
            子元素
        </div>
    </div>
    <script>
        var parent = document.getElementById('parent');
        var child = document.getElementById('child');
        document.body.addEventListener('click', function (e) {
            var ev = e || window.event;//获取事件对象,后者兼容IE的写法
            //console.log(e);
            var target = ev.target || ev.srcElement;//获取事件源对象,后者兼容IE
            //console.log(target);
            console.log('事件冒泡——click body');
        });
        parent.addEventListener('click', function () {
            console.log('事件冒泡——click parent');
        }, false);
        child.addEventListener('click', function () {
            console.log('事件冒泡——click child');
        });
    </script>
</body>
</html>

点击body元素结果是:
在这里插入图片描述
点击parent元素结果是:
在这里插入图片描述
点击child元素结果是:
在这里插入图片描述
事件触发顺序是由内到外,这就是事件冒泡。child -> parent -> body。

将js代码改为如下:

document.body.addEventListener('click', function (e) {
            var ev = e || window.event;//获取事件对象,后者兼容IE的写法
            var target = ev.target || ev.srcElement;//获取事件源对象,后者兼容IE
            console.log('事件捕获——click body');
        },true);
        parent.addEventListener('click', function () {
            console.log('事件捕获——click parent');
        }, true);
        parent.addEventListener('click', function () {
            console.log('事件传播——click parent');
        }, false);
        child.addEventListener('click', function () {
            console.log('事件冒泡——click child');
        },false);

点击body元素结果是:
在这里插入图片描述
点击parent元素结果是:
在这里插入图片描述
点击child元素结果是:
在这里插入图片描述
父元素通过事件捕获的方式注册了click事件,所以在事件捕获阶段就会触发,然后到了目标阶段,即事件源,之后进行事件冒泡,parent同时也用冒泡方式注册了click事件,所以这里会触发冒泡事件,最后到根节点(body)。这就是整个事件流程。

3、阻止事件冒泡

兼容IE的写法:

function stopPropagationSelf(e) {
            if (e && e.stopPropagation) {
                e.stopPropagation();
            } else {//IE方式取消事件冒泡
                window.event.cancelBubble = true;
            }
        }

4、阻止默认事件

兼容IE的写法:

 function preventDefaultSelf(e) {
            if (e && e.preventDefault) {
                e.preventDefault();
            } else {//IE方式阻止默认事件
                window.event.returnValue = false;
            }
        }

5、事件委托

事件委托也称事件代理,事件委托就是利用事件冒泡原理,只指定一个事件处理程序,就可以管理某一类型的所有事件。
一般来讲,会把一个或一组元素的事件委托到他的父层或更外层元素上,真正绑定事件的是外层元素,当事件响应(事件捕获)到真正需要绑定的元素上时,会通过事件冒泡机制,从而触发它的外层元素的绑定事件,然后在外层元素上去执行事件处理函数。
例子:
在这里插入图片描述
现在有如上一个todolist,需要有以下功能:

1、点击‘add’按钮时,列表中新增item,内容为文本框输入内容
2、todo Item 点击’完成’按钮时自动删除

我们知道的给DOM绑定事件的方法有以下几种:

嵌入html
这种很明显缺点是代码耦合,不便于维护和开发

<li>事件1 <button onclick="complete">完成</button></li>

DOM绑定
这种比较常见,比较简单易懂,而且兼容性较好,但是也有缺陷,只能实现一个绑定,也就是说我们再为element绑定第二个click事件时候,会覆盖掉之前的click事件

oBtn.onclick = complete

使用事件监听函数

oBtn.addEventListener('click',complete)
兼容性写法:
if (element.addEventListener) {
      element.addEventListener(type, handler, false);
  } else if (element.attachEvent) {
          element.attachEvent("on" + type, handler);
 } else {
     element["on" + type] = handler;
  }

需求很简单,但是有两点需要注意:

如果给‘完成’按钮嵌入DOM事件,因为不断有新item的生成,每次生成都要重新绑定,代码不便管理。
如果给‘完成’按钮绑定事件,则需要循环遍历每一个‘完成’按钮,不断访问DOM,按钮越多,访问次数越多,性能越低。

为了解决上述两个问题,‘事件代理’便是完美的解决方案。
实现思路
将事件绑定到父元素ul上,当用户点击按钮时,通过事件流,冒泡到父元素ul,从而执行回调。

<!DOCTYPE html>
<html>
<head>
    <title>事件委托</title>
    <style>
        body,html{
            margin:0px;
            padding:0px;
        }
       
    </style>
</head>
<body>
    <div class="container">
        <h1>TODO List</h1>
        <input type="text" id="itemInput"/><input type="button" value="add" onclick="addItem();"/>
        <ul id="parentUl">
            <li>事情1<button>完成</button></li>
            <li>事情2<button>完成</button></li>
        </ul>
    </div> 
    <script>
        var Ul = document.getElementById('parentUl');
        Ul.addEventListener('click', function (e) {
            var ev = e || window.event;
            var target = ev.target || ev.srcElement;
            if (target.tagName.toLowerCase() === 'button') {                
                var liNode = target.parentNode || target.parentElement;
                Ul.removeChild(liNode);
            }
        });
        function addItem() {
            var itemInput = document.getElementById('itemInput');
            var item = document.createElement('li');
            item.innerHTML = itemInput.value + '<button>完成</button>'
            Ul.appendChild(item);
        }
    </script>
</body>
</html>

6、事件委托的优点

1、只绑定一次事件,无需频繁访问DOM,提高性能。
2、当有新的DOM生成时,无需重复绑定事件,代码清晰度高。
缺点:
很多事件是不能冒泡的,比如说focus、blur、load本身就没有冒泡的特性,自然就不能用事件委托了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值