在浏览器或文档某个元素发生某个特定情况的瞬间,会作为一个事件进行广播,我们可以对其添加监听来处理特定的事件。

事件流

事件流描述了页面中接收事件的顺序。

整个事件流包含了三个阶段:事件捕获阶段、事件目标阶段和事件冒泡阶段。

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="myDiv">Click me</div>
</body>
</html>

如果我们点击了上面代码中的div元素,实际的事件流如下:

  1. 捕获阶段:1、2、3属于捕获阶段;
  2. 目标阶段:4属于目标阶段;
  3. 冒泡阶段:5、6、7属于冒泡阶段;

事件处理

在HTML中,事件的处理有多种方法可以用来实现。下面我们一一来看。

HTML事件处理

即直接在HTML中指定处理的函数:

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="myDiv" onclick="alert(this.id)//myDiv">Click me</div>
</body>
</html>

也可以指定为一个外部定义的函数:

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<script type="text/javascript">
function divClickHandler(event) {
console.log(this.id); // undefined
console.log(event.type); // click
}
</script>
<div id="myDiv" onclick="divClickHandler(event)">Click me</div>
</body>
</html>

注意这种方式的话,作用域是全局的,而上面的写法可以通过this.id取到点击的对象的id;

另外,事件会有一个名为event的参数,可以传递给处理的函数来得知更加丰富的事件信息。

DOM0级事件处理

实际上就是HTML事件处理的代码指定写法,如下:

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="myDiv" onclick="divClickHandler(event)">Click me</div>
<script type="text/javascript">
function divClickHandler(event) {
console.log(this.id); // myDiv
console.log(event.type); // click
} var myDiv = document.getElementById("myDiv");
myDiv.onclick = divClickHandler;
</script>
</body>
</html>

使用该方法可以取消事件的绑定,如下:

 myDiv.onclick = null;

这种方式比较简单,但是无法绑定2个函数。

DOM2级事件处理

新的标准中,关于事件的处理采用了观察者模式,添加了addEventListener和removeEventListener两个方法,这两个方法都接受3个参数:

  1. 事件类型
  2. 处理该事件的函数
  3. 最后一个布尔值:true表示捕获阶段调用,false表示冒泡阶段调用,默认false,需要注意目标阶段也算在冒泡阶段中

我们看下例子:

 var divClickHandler = function(event) {
console.log(this.id); // myDiv
console.log(event.type); // click
} var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("click", divClickHandler);

需要注意的是使用该方法可以为一个事件类型添加多个事件处理监听,使用removeEventListener可以移除添加了的监听,我们再看一个例子:

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="myGroup">
<div id="myDiv">Click me</div>
</div>
<script type="text/javascript">
function buhuo(event) {
console.log(1);
}
function maopao(event) {
console.log(2);
} var myGroup = document.getElementById("myGroup");
myGroup.addEventListener("click", buhuo, true);
myGroup.addEventListener("click", maopao); function divClickHandler(event) {
console.log(3);
} var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("click", divClickHandler);
</script>
</body>
</html>

点击后输出如下:

 1
3
2

IE事件处理

在早期的IE中,使用的是attachEvent和detachEvent,由于不是标准的方法,所以这里就不记录了,有兴趣的童鞋可以自行搜索。

事件对象

在触发DOM上的某个事件时,将会产生一个事件对象event,这个对象包含所有与当前事件有关的信息。

DOM中的事件对象

无论是DOM0还是DOM2级,都会传入event对象,如下:

 var myDiv = document.getElementById("myDiv");
myDiv.onclick = function(event) {
console.log(event.type); // click
}
myDiv.addEventListener("click", divClickHandler);
function divClickHandler(event) {
console.log(event.type); // click
}

即使直接写在HTML中(DOM0级的另一种写法),也一样存在event事件对象:

<div id="myDiv" onclick="console.log(event.type)">Click me</div>

target与currentTarget

在事件处理函数中,this对象始终指向currentTarget对象,target对象包含事件的实际目标(即处于目标阶段的对象)。而currentTarget对象指向添加了当前事件处理函数的对象。

我们来看下面的例子:

 <!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>
<body id="myBody">
<div id="myGroup">
<div id="myDiv" onclick>Click me</div>
</div>
<script type="text/javascript">
var body = document.body;
var myGroup = document.getElementById("myGroup");
var myDiv = document.getElementById("myDiv"); body.addEventListener("click", onBodyClick);
function onBodyClick(event) {
console.log("click body: " + event.currentTarget.id + ", " + event.target.id);
} myGroup.addEventListener("click", onMyGroupClick);
function onMyGroupClick(event) {
console.log("click myGroup: " + event.currentTarget.id + ", " + event.target.id);
} myDiv.addEventListener("click", onMyDivClick);
function onMyDivClick(event) {
console.log("click myDiv: " + event.currentTarget.id + ", " + event.target.id);
}
</script>
</body>
</html>

点击Click me后打印如下:

click myDiv: myDiv, myDiv
click myGroup: myGroup, myDiv
click body: myBody, myDiv

取消默认行为

事件可以取消默认行为,什么是默认行为呢?比如一个设定了目标地址的a标签,默认点击后会打开对应的地址,这个不是我们添加的行为就是默认行为。我们可以通过event对象的cancelable来判断是否可以取消默认行为,为true表示可以取消,调用preventDefault方法就可取消默认行为,如下:

 <!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>
<body>
<a id="myLink" href="http://www.baidu.com">link</a>
<script type="text/javascript">
var myLink = document.getElementById("myLink");
myLink.addEventListener("click", linkClickHandler); function linkClickHandler(event) {
if (event.cancelable)
event.preventDefault();
}
</script>
</body>
</html>

正常情况下点击link会进行跳转,加入取消默认事件的代码后点击link后就没有跳转网页的执行了。

取消事件冒泡

我们知道事件是会向根对象进行冒泡的,我们同样可以通过代码暂停事件继续进行冒泡,有两个方法可以使用:

  • stopPropagation:取消事件向父级冒泡;
  • stopImmediatePropagation:取消事件向父级及同级的冒泡;

这两个方法都是在bubbles属性为true时可以使用。

 <!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>
<body>
<div id="myDiv">click me</div>
<script type="text/javascript">
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("click", divClickHandler);
myDiv.addEventListener("click", divClickHandler2); function divClickHandler(event) {
if (event.bubbles)
event.stopPropagation();
console.log("1");
} function divClickHandler2(event) {
console.log("2");
} document.body.addEventListener("click", bodyClickHandler); function bodyClickHandler(event) {
console.log("3");
}
</script>
</body>
</html>

调用stopPropagation后打印“1”和“2”,表示阻止了向父级的冒泡,但是同级的事件监听仍然可以接收事件。

修改代码如下后:

 function divClickHandler(event) {
if (event.bubbles)
event.stopImmediatePropagation();
console.log("1");
}

只会打印“1”表示阻止了后续的所有事件,包含同级及父级的事件。

事件类型

浏览器中,已经定义了许多事件相关的类型,大体如下:

http://www.w3school.com.cn/jsref/dom_obj_event.asp

内存和性能

这里讨论下提升性能的方法。

事件委托

在一些其它语言的GUI项目中,为每个按钮添加事件处理函数是很正常且也不会影响性能的,但是在JS中,每个函数都是对象,如果为每个点击项都额外添加一个处理函数,无疑会增加消耗,这时采用冒泡的特性在父级对象上添加一个函数,通过target属性的id来区分不同的点击项可以减少页面中的处理函数了。

及时移除不需要的事件监听

对于不使用了的事件监听,请及时移除,比如在div内的一个元素存在监听,在没有移除监听之前就更改了innerText导致移除了内部元素但是没有移除监听就有可能导致移除元素无法垃圾回收。

模拟事件

在JS中,我们还可以通过代码创建一个特定的事件进行播放来进行事件的模拟,下面我们来看看如何模拟一个系统的事件。

模拟鼠标事件

我们看看模拟鼠标事件的代码:

 <!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>
<body>
<a id="myLink" href="http://www.baidu.com">click me</a>
<script type="text/javascript">
setTimeout(function(){
var myLink = document.getElementById("myLink");
//创建鼠标事件
var evt = document.createEvent("MouseEvents");
//初始化鼠标事件
evt.initMouseEvent("click", true, true, document.defaultView);
//在目标对象上播放
myLink.dispatchEvent(evt);
}, 3000);
</script>
</body>
</html>

3秒之后会打开百度首页。

initMouseEvent的参数描述点击这里

模拟其它事件

注意createEvent的参数,使用“MouseEvents”创建鼠标事件,使用“HTMLEvents”可以创建页面事件,使用“MutationEvents”可以创建DOM的变动事件。具体的使用方法可以自行搜索。

自定义事件

同样的,我们也可以创建自定义的事件,如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>
<body>
<a id="myLink" href="http://www.baidu.com">click me</a>
<script type="text/javascript">
document.body.addEventListener("myEvent", function(event){
console.log("onMyEvent name: " + event.detail.name);
}); setTimeout(function(){
var myLink = document.getElementById("myLink");
//创建自定义事件
var evt = document.createEvent("CustomEvents");
//初始化自定义事件
evt.initCustomEvent("myEvent", true, true, {name:"Li Lei"});
//在目标对象上播放
myLink.dispatchEvent(evt);
}, 3000);
</script>
</body>
</html>

但是,CustomEvents并不是所有浏览器都支持的事件类型,比如Chrome就不支持,所以,当我们需要使用到跨浏览器的自定义事件时,一般还是使用观察者模式来实现,当然自己实现的话就不能拥有冒泡的功能了。

HTML5学习笔记(二十五):事件的更多相关文章

  1. python3.4学习笔记(二十五) Python 调用mysql redis实例代码

    python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...

  2. Java基础学习笔记二十五 MySQL

    MySQL 在dos中操作mysql 连接mysql命令: mysql -uroot -p密码 ,连接OK,会出现mysql> 对数据库的操作 创建一个库 create database 库名 ...

  3. Java学习笔记二十五:Java面向对象的三大特性之多态

    Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...

  4. PHP学习笔记二十五【类的继承】

    <?php //定义父类 class Stu{ public $name; protected $age; protected $grade; private $address;//私有变量不会 ...

  5. HTML5学习笔记(十五):方法

    在一个对象中绑定函数,称为这个对象的方法. 在JavaScript中,对象的定义是这样的: var xiaoming = { name: '小明', birth: 1990 }; 但是,如果我们给xi ...

  6. angular学习笔记(二十五)-$http(3)-转换请求和响应格式

    本篇主要讲解$http(config)的config中的tranformRequest项和transformResponse项 1. transformRequest: $http({ transfo ...

  7. python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法

    python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...

  8. 学习笔记:CentOS7学习之二十五:shell中色彩处理和awk使用技巧

    目录 学习笔记:CentOS7学习之二十五:shell中色彩处理和awk使用技巧 25.1 Shell中的色彩处理 25.2 awk基本应用 25.2.1 概念 25.2.2实例演示 25.3 awk ...

  9. Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例

    目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装项目其它需要包 清除冗余文件并重新规划项目目录 配置文件 规划示例路由,并新建相关文件 实现数据访问和业务逻辑相关方法 编写mys ...

  10. [转]Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例

    本文转自:https://www.cnblogs.com/zhongweiv/p/nodejs_koa2_webapp.html 目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装 ...

随机推荐

  1. linux上源码编译安装mysql-5.6.28

    在 linux 上编译安装 mysql-.tar.gz http://www.mysql.com/ mysql下载地址: http://www.mysql.com/downloads/mysql/#d ...

  2. Android 本地播放器

    发布时间:2018-09-06   技术:Glide+pinyin4j+SwipeDelMenuLayout   概述 这是一款Android 端的本地音乐播放器,界面风格有模仿网易云音乐.bilib ...

  3. PLSQL Developer启动失败

    原因:和打印服务冲突 禁掉打印服务,不过打印功能是不行了

  4. VMware Workstation 10.0 简中绿色精简版

    VMware Workstation是强大的虚拟机软件,能在一台机器上同时运行二个或更多Windows.DOS.LINUX系统,并进行开发.测试.部署新的应用程序.VMware10.0 延续VMwar ...

  5. ubuntu中查看各种设备和资源的命令汇总

    一.系统信息     1.查看内核信息:                                           $uname -a     2.查看操作系统版本:             ...

  6. java struts2入门学习---常用标签学习总结

    jsp页面中引入标签: <%@ taglib uri="/struts-tags" prefix="s"%> 常用标签知识点总结: <s:fi ...

  7. linux shell 脚本攻略学习16--wc命令详解,tree命令详解

    在文本处理的工作中,统计文件的行数,单词数和字符数非常有用.而对于开发人员本身来说,统计LOC(line of code ,代码行数)是一件重要的工作.linux中有什么命令可以帮助我们做统计呢?没错 ...

  8. java unicode转码为中文 实例

    package com.infomorrow.parser_report; import org.junit.Test; public class Decode { @Test public void ...

  9. HDU 4301 Divide Chocolate (DP + 递推)

    Divide Chocolate Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  10. ios app: 使用企业license设置发布app的过程

      ios开发者证书与企业证书的内容,关系,以及ios app 使用企业license设置发布app的过程 iOS是一个非常封闭的系统.授权文件(.mobileprovision)和签名证书文件(.c ...