1、事件的基本概念

  事件是指在文档或者浏览器中发生的一些特定交互瞬间,比如打开某一个网页,浏览器加载完成后会触发 load 事件,当鼠标悬浮于某一个元素上时会触发 hover 事件,当鼠标点击某一个元素时会触发 click 事件等等。

  事件处理就是当事件被触发后,浏览器响应这个事件的行为,而这个行为所对应的代码即为事件处理程序。

2、事件操作:监听与移除监听

2.1 监听事件

  浏览器会根据一些事件作出相对应的事件处理,事件处理的前提是需要监听事件,监听事件的方法主要有以下三种:

2.1.1 HTML 内联属性

  即在 HTML 元素里直接填写与事件相关的属性,属性值为事件处理程序。示例如下:

<button onclick="console.log('You clicked me!');"></button>

  这种方式将 HTML 代码与 JavaScript 代码耦合在一起,不利于代码的维护,所以应该尽量避免使用这样的方式。

2.1.2 DOM 属性绑定

  通过直接设置某个 DOM 节点的属性来指定事件和事件处理程序,上代码:

const btn = document.getElementById("btn");
btn.onclick = function(e) {
console.log("You clicked me!");
};

  首先获得 btn 这个对象,通过给这个对象添加 onclick 属性的方式来监听 click 事件,这个属性值对应的就是事件处理程序。这段程序也被称作 DOM 0 级事件处理程序。

2.1.3 事件监听函数

  标准的事件监听函数如下:

const btn = document.getElementById("btn");
btn.addEventListener("click", () => {
console.log("You clicked me!");
}, false);

  上面的示例表示先获得表示节点的 btn 对象,然后在这个对象上面添加了一个事件监听器,当监听到 click 事件发生时,则调用回调函数,即在控制台输出 "You clicked me!",这段程序也被称作 DOM 2 级事件处理程序。

2.2 移除事件监听

  在为某个元素绑定了一个事件后,如果想接触绑定,则需要用到 removeEventListener 方法。如下列代码所示:
const handler = function() {
// handler logic
}
const btn = document.getElementById("btn"); btn.addEventListener("click", handler);
btn.removeEventListener("click", handler);

  需要注意的是,绑定事件的回调函数不能是匿名函数,必须是一个已经被声明的函数,因为解除事件绑定时需要传递这个回调函数的引用。

3.事件触发过程

   事件流描述了页面接收事件的顺序。事件流包含三个过程,分别是捕获阶段、目标阶段和冒泡阶段。

    首先发生的是事件捕获阶段,为截获事件提供了机会,然后是目标接收事件,最后是冒泡阶段。下图形象地说明这个过程:

3.1 捕获阶段

  当我们对 DOM 元素进行操作时,比如鼠标点击、悬浮等,就会有一个事件传输到这个 DOM 元素,这个事件从 Window 开始,依次经过 docuemnt、html、body,再不断经过子节点直到到达目标元素,从 Window 到达目标元素父节点的过程称为捕获阶段,注意此时还未到达目标节点。

  addEventListener(eventName, handler, useCapture) 函数。第三个参数是 useCapture,代表是否在捕获阶段进行事件处理。

   如果是 true,在捕获阶段进行事件处理,如果是 false, 则在冒泡阶段进行事件处理。默认是 false。

   如下代码所示:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件流</title>
<style type="text/css">
#wrap{
width: 200px;
height: 200px;
background: orange;
}
#outer{
position: relative;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background: #eeddff;
}
#inner{
position: relative;
top: 25px;
left: 25px;
width: 50px;
height: 50px;
background: #44ddff;
}
</style>
</head>
<body>
<div id="wrap">
<div id="outer">
<div id="inner"></div>
</div>
</div>
<script type="text/javascript"> var wrap = document.getElementById('wrap');
wrap.addEventListener('click',function () {
console.log('wrap');
},true);
var outer = document.getElementById('outer');
outer.addEventListener('click',function () {
console.log('outer');
},true);
var inner = document.getElementById('inner');
inner.addEventListener('click',function () {
console.log('inner');
},true);
</script>
</body>
</html>

  结果如下所示:

  如果点击最里面的蓝色块,事件会从最外层父元素向内捕获,控制台打印出的结果如下:

3.2 目标阶段

  捕获阶段结束时,事件到达了目标节点的父节点,最终到达目标节点,并在目标节点上触发了这个事件,这就是目标阶段。

  事件触发的目标节点为最底层的节点。

<div>
<p>你猜,目标在这里还是<span>那里</span>。</p>
</div>

  上面代码中,当我们点击“那里”的时候,目标节点是<span></span>,点击“这里”的时候,目标节点是<p></p>,而当我们点击<p></p>区域之外,<div></div>区域之内时,目标节点就是<div></div>。

3.3 冒泡阶段

  当事件到达目标节点之后,就会沿着原路返回,这个过程有点类似水泡从水底浮出水面的过程,所以称这个过程为冒泡阶段。

  addEventListener(eventName, handler, useCapture) 函数。第三个参数是 useCapture,代表是否在捕获阶段进行事件处理。

  如果是 false, 则在冒泡阶段进行事件处理。如果是 true,在捕获阶段进行事件处理,默认是 false。

  如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件流</title>
<style type="text/css">
#wrap{
width: 200px;
height: 200px;
background: orange;
}
#outer{
position: relative;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background: #eeddff;
}
#inner{
position: relative;
top: 25px;
left: 25px;
width: 50px;
height: 50px;
background: #44ddff;
}
</style>
</head>
<body>
<div id="wrap">
<div id="outer">
<div id="inner"></div>
</div>
</div>
<script type="text/javascript"> var wrap = document.getElementById('wrap');
wrap.addEventListener('click',function () {
console.log('wrap');
},false);
var outer = document.getElementById('outer');
outer.addEventListener('click',function () {
console.log('outer');
},false);
var inner = document.getElementById('inner');
inner.addEventListener('click',function () {
console.log('inner');
},false);
</script>
</body>
</html>

  结果如下所示:

  如果点击最里面的蓝色块,事件会冒泡到父元素,控制台打印出的结果如下:

 

4、事件委托

  事件的冒泡机制,我们可以利用这一特性来提高页面性能,事件委托便事件冒泡是最典型的应用之一。

  JavaScript 中,事件的委托表示给元素的父级或者祖级,甚至页面,由他们来绑定事件,然后利用事件冒泡的基本原理,通过事件目标对象进行检测,然后执行相关操作。如下列代码所示:

<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li // 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase() === 'li') {
console.log('the content is: ', target.innerHTML);
}
});

   上列代码中,列表项的点击事件均委托给了父元素 <ul id="list"></ul>。

   target 元素则是在 #list 元素之下具体被点击的元素,然后通过判断 target 的一些属性(比如:nodeName,id 等等)可以更精确地匹配到某一类 #list li 元素之上。

  为什么需要事件委托:

  1.减少事件绑定。上面的例子中,也可以分别给每个列表项绑定事件,但利用事件委托的方式不仅省去了一一绑定的麻烦,也提升了网页的性能,因为每绑定一个事件便会增加内存使用。

  2.可以动态监听绑定。上面的例子中,我们对 5 个列表项进行了事件监听,当删除一个列表项时不需要单独删除这个列表项所绑定的事件,而增加一个列表项时也不需要单独为新增项绑定事件。

5.阻止事件冒泡

  事件委托是事件冒泡的一个应用,但有时候我们并不希望事件冒泡。想要解决这个问题,只需要加一行代码:

const ele = document.getElementById("ele");
ele.addEventListener("click", function(e) {
console.log("ele-click");
e.stopPropagation(); // 阻止事件冒泡
}, false); document.addEventListener("click", function(e) {
console.log("document-click");
}, false);

6、event 对象

  Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。

  当一个事件被触发的时候,就会创建一个事件对象。

  比如下面代码中,打印出事件对象:

<div id="list">
<li>Item 1</li>
<li>Item 2</li>
</div>
<script>
const list = document.getElementById("list");
list.addEventListener("click", function(e) {
console.log(e);
});
</script>

JavaScript 浏览器中的事件的更多相关文章

  1. JavaScript(jQuery)中的事件委托

    一:什么是事件委托? 事件委托是利用事件冒泡,只指定一个事件处理程序来管理某一类型的所有事件. 二:为什么要用事件委托? 1.在JavaScript中添加到页面上的事件处理程序的个数直接关系到页面的整 ...

  2. 关于 Chrome 浏览器中 onresize 事件的 Bug

    我在写插件时用到了 onresize 事件,在反复地测试后发现该事件在 Chrome 及 Opera(内核基本与 Chrome 相同,以下统称 Chrome)浏览器打开时就会执行,这种情况也许不能算作 ...

  3. UC浏览器中touch事件的异常记录

    以前也在UC上面栽过几个坑,不过都是页面显示方面的.上个周的时候,商品详情页重做,要添加个上拉显示详情的效果. 有两个条件需要判断: 1.是否到达底部: 2.到达底部之后拖动的y轴距离. 效果写完后, ...

  4. JavaScript 中的事件类型5(读书笔记思维导图)

    Web 浏览器中可能发生的事件有很多类型.如前所述,不同的事件类型具有不同的信息,而“ DOM3级事件”规定了以下几类事件. UI(User Interface,用户界面)事件:当用户与页面上的元素交 ...

  5. JavaScript 中的事件类型4(读书笔记思维导图)

    Web 浏览器中可能发生的事件有很多类型.如前所述,不同的事件类型具有不同的信息,而“ DOM3级事件”规定了以下几类事件. UI(User Interface,用户界面)事件:当用户与页面上的元素交 ...

  6. JavaScript 中的事件类型3(读书笔记思维导图)

    Web 浏览器中可能发生的事件有很多类型.如前所述,不同的事件类型具有不同的信息,而“ DOM3级事件”规定了以下几类事件. UI(User Interface,用户界面)事件:当用户与页面上的元素交 ...

  7. JavaScript 中的事件类型2(读书笔记思维导图)

    Web 浏览器中可能发生的事件有很多类型.如前所述,不同的事件类型具有不同的信息,而“ DOM3级事件”规定了以下几类事件: UI(User Interface,用户界面)事件:当用户与页面上的元素交 ...

  8. JavaScript 中的事件类型1(读书笔记思维导图)

    Web 浏览器中可能发生的事件有很多类型.如前所述,不同的事件类型具有不同的信息,而“ DOM3级事件”规定了以下几类事件. UI(User Interface,用户界面)事件:当用户与页面上的元素交 ...

  9. Javascript中的事件二

    <!------------------示例代码一---------------------><!DOCTYPE html PUBLIC "-//W3C//DTD XHTM ...

随机推荐

  1. Tsinghua 2018 DSA PA3简要题解

    CST2018 3-1-1 Sum (15%) 简单的线段树,单点修改,区间求和. 很简单. CST2018 3-1-2 Max (20%) 高级的线段树. 维护区间最大和,区间和,左边最大和,右边最 ...

  2. [NOIP2014D1]

    T1 Problem 洛谷 Solution 一道非常裸的模拟题.直接枚举每次猜拳就可以了. Code #include<cmath> #include<cstdio> #in ...

  3. React中this.setState是同步还是异步?为什么要设计成异步?

    在使用react的时候,this.setState为什么是异步呢? 一直以来没有深思这个问题.昨天就此问题搜索了一下. react创始人之一 Dan Abramovgaearon在GitHub上回答了 ...

  4. 如何使用ESP8266、ESP8285做一个WiFi中继(WiFi信号放大器)

    准备工作 准备一个深圳四博智联科技有限公司的ESP-F 模组.或者四博智联科技的NODEMCU 当我们拿到ESP-F模块后,可以按照以下接线进行测试: 即 VCC.EN 接 3.3v.GPIO15 G ...

  5. inner join on (程序测试验证结果。) _学习贴

    inner join on  两张表:机制就是第一张表的每一条数据,都会去和第二章表的每一条数据 依次进行匹配.匹配成功,就会显示出来. (程序测试验证结果.) 数据库连接 1 对 1 create ...

  6. NFS、FTP介绍

    第二十五课 NFS.FTP介绍 目录 一. NFS介绍 二.NFS服务端安装配置 三.NFS配置选项 四.exportfs命令 五.NFS客户端问题 六.FTP介绍 七.使用vsftpd搭建ftp 八 ...

  7. js中获取时间new Date()详细介绍

    var myDate = new Date();myDate.getYear(); //获取当前年份(2位)myDate.getFullYear(); //获取完整的年份(4位,1970-????)m ...

  8. 20165214 2018-2019-2 《网络对抗技术》Exp3 免杀原理与实践 Week5

    <网络对抗技术>Exp3 免杀原理与实践 Week5 一.实验内容 1.正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,加壳工具,使用shell ...

  9. Shell 字符串处理

    字符串处理方式 计算字符串长度 获取子串在字符串中的索引位置 计算子串长度 抽取(截取)字串 1.计算字符串长度,有两种方式 $ ${#string} $ expr length "$str ...

  10. 微信小程序windowHeight的值在ios和android平台不一致问题解决办法

    开发中遇到一个业务需求,需要把页面顶部.底部固定,中间的scroll-view内部滚动.要满足这个需求,需要根据屏幕高度计算中间的scroll-view高度.结果悲催地发现,使用 wx.getSyst ...