从一个事件绑定说起 - DOM
事件绑定的方式
给 DOM 元素绑定事件分为两大类:在 html 中直接绑定 和 在 JavaScript 中绑定。
Bind in HTML
在 HTML 中绑定事件叫做内联绑定事件,HTML 的元素中有如 onclick 这样的 on*** 属性,它可以给这个 DOM 元素绑定一个类型的事件,主要是这样的:
<div onclick="***">CLICK ME</div> |
这里的 *** 有两种形式:
- 用字符串表示一段函数:
<div onclick="var a = 1; console.log(a); console.log(this);">CLICK ME</div> |
点击可以发现,console:
1 |
var a = 1; console.log(a); console.log(this); 这一段字符串被当作 js 执行了,同时 this 指向当前这个点击的元素。
- 用函数名表示:
<div onclick="foo(this)">CLICK ME</div> |
这里需要添加 script 去定义函数:
<script> |
可以观察到,console:
<div onclick="var a = 1; console.log(a); console.log(this);">CLICK ME</div> |
这里的 this 指向了全局,传入的参数是点击的 DOM 元素,其实和第一种方式是一样的,都是在 onclick= 后面指向了一段js的字符串,不同的是在这个字符串中是执行了一个函数名,而这个函数我们在全局中定义了,所以点击的时候可以执行,然后传入的参数 this 也就是一样的道理了。
或者多说一句,这里的字符串才是真正赋值给 onclick 的函数,这里我们是在函数里面再执行了 foo 函数。
然而这内联的方式绑定时间不利于分离,所以一般我们不推荐这种做法,所以也就不再多阐述了
Bind in JavaScript
dom.onclick
先上栗子:
<div id="clickme">CLICK ME</div> |
document.getElementById('clickme').onclick = function (e) {
|
观察 console:
clickme |
首先,我们获取到了 dom 元素,然后给它的 onclick 属性赋值了一个函数;
点击 dom 我们发现那个函数执行了,同时发现函数中的 this 是指向当前的这个 dom 元素;
细细一想,其实这和前面用的在 html 中 内联 绑定函数是一样的,我们同样是给 dom 的 onclick 属性赋值一个函数,然后函数中的 this 指向当前元素,只是这个过程这里我们是在 js 中做的;
而还有一点区别就是前面的是赋值一段 js 字符串,这里是赋值一个函数,所以可以接受一个参数:event,这个参数是点击的事件对象。
用赋值绑定函数的一个缺点就是它只能绑定一次:
document.getElementById('clickme').onclick = function (e) {
|
可以看到这里只打印了一次 clickme。
addEventListener
这个才是我们需要重点介绍的一个函数
语法
target.addEventListener(type, listener[, useCapture]); |
target: 表示要监听事件的目标对象,可以是一个文档上的元素Document本身,Window或者XMLHttpRequest;type: 表示事件类型的字符串,比如:click、change、touchstart…;listener: 当指定的事件类型发生时被通知到的一个对象。该参数必是实现 EventListener 接口的一个对象或函数。useCapture: 设置事件的 捕获或者冒泡 (后文阐述) ,true: 捕获,false: 冒泡*,默认为false。
简单栗子
<div id="clickme">CLICK ME</div> |
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1);
function foo1(event) {
|
观察 console:
clickme |
监听函数中的 this 指向当前的 dom 元素,函数接受一个 event 参数。
绑定函数
绑定多个函数
addEventListener 可以给同一个 dom 元素绑定多个函数:
<div id="clickme">CLICK ME</div> |
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1);
|
可以看到 console:
111 |
我们可以看到两个函数都执行了,并且执行顺序按照绑定的顺序执行。
改变一下,如果我们的 useCapture 参数不同呢?
看下面 3 组对比:
1
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1, true);
|
2
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1, true);
|
3
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1, false);
|
可以看到,console 并没有改变,所以执行顺序只和绑定顺序有关,和 useCapture 无关。
结论:
我们可以给一个 dom 元素绑定多个函数,并且它的执行顺序按照绑定的顺序执行。
同一个元素绑定同一个函数
我们给一个 dom 元素绑定同一个函数两次试试:
<div id="clickme">CLICK ME</div> |
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1);
|
观察 console:
111 |
可以看到函数只执行了一次;
换一种方式:
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1, true);
|
观察 console:
111 |
可以看到函数执行了两次。
结论:
我们可以给一个 dom 元素绑定同一个函数,最多只能绑定 useCapture 类型不同的两次。
IE下使用attachEvent/detachEvent
addEventListener 只支持到 IE 9,所以为了兼容性考虑,在兼容 IE 8 以及以下浏览器可以用 attachEvent 函数,和 addEventListener 函数表现一样,除了它绑定函数的 this 会指向全局这个缺点以外
事件执行顺序的 PK
1. addEventListener 和 dom.onclick
<div id="clickme">CLICK ME</div> |
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1, true);
|
观察 console:
111 |
可见执行顺序只和绑定顺序有关
2. addEventListener 间的比较
事件的解绑
与事件绑定相对应的就是事件解绑了。
1. 通过 dom 的 on** 属性设置的事件
对于 Bind in HTML 和 dom.onclick 绑定的事件都可以用 dom.onclick = null 来解绑事件。
2. removeEventListener
通过 addEventListener 绑定的事件可以使用 removeEventListener 来解绑, removeEventListener 接受的参数和 addEventListener 是一样的
<div id="clickme">CLICK ME</div> |
var clickme = document.getElementById('clickme');
clickme.addEventListener('click', foo1);
function foo1(event) {
|
这里发现事件并没有取消绑定,发现 removeEventListener 的 useCapture 的参数原来和绑定时候传入的不一致,我们改成 false 之后发现事件取消了。
结论:
对于使用 removeEventListener 函数解绑事件,需要传入的 listener useCapture 应和 addEventListener 一致才可以解绑事件。
3. detachEvent
与 attachEvent 对应
DOM 事件

<!DOCTYPE html> |
事件冒泡
事件开始时由最具体的元素接受,然后逐级向上传播到较为不具体的节点。
比如上面的 HTML ,冒泡的顺序: div3 -> div3 -> div1 -> body -> html -> document (-> window)
事件捕获
事件捕获的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件。与事件冒泡的顺序相反。
比如上面的 HTML ,捕获的顺序: document -> html -> body -> div1 -> div2 -> div3
DOM事件流
DOM事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。
回到 addEventListener
我们来做几个小对比:
<div id="wrap"> |
栗子 1
document.getElementById('wrap').addEventListener('click', foo1, false);
|
console:
222 |
这里两个事件都是冒泡类型,所以是从内到外;
栗子 2
document.getElementById('wrap').addEventListener('click', foo1, true);
|
console:
111 |
这里两个事件都是捕获类型,所以是从外到内;
栗子 3
document.getElementById('wrap').addEventListener('click', foo1, false);
|
console:
222 |
wrap 事件是冒泡,clickme 事件是捕获,根据 dom 的事件流,先执行了捕获阶段(这里是目标阶段)再到冒泡阶段。
栗子 4
document.getElementById('wrap').addEventListener('click', foo1, true);
|
console:
111 |
clickme 事件是冒泡,wrap 事件是捕获,根据 dom 的事件流,先执行了捕获阶段(这里是目标阶段)再到冒泡阶段。
阻止 冒泡/捕获
<div id="wrap"> |
document.getElementById('wrap').addEventListener('click', foo1);
|
从一个事件绑定说起 - DOM的更多相关文章
- Javascript 事件对象(四)一个事件绑定多个不同的函数
给一个对象绑定多个事件处理函数: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-T ...
- vue中把一个事件绑定到子组件上
官网上是这样描述的 你可能有很多次想要在一个组件的根元素上直接监听一个原生事件.这时,你可以使用 v-on的 .native 修饰符 父组件App.vue <template> <d ...
- jQuery中事件绑定到bind、live、delegate、on方法的探究
1. 给页面上的某个元素绑定事件,最初采用下面的方式实现: $(‘selector’).click(function(){ //code }); 缺点: 不能同时绑定多个事件,不能绑定动态的元素. 后 ...
- dojo事件驱动编程之事件绑定
什么是事件驱动? 事件驱动编程是以事件为第一驱动的编程模型,模块被动等待通知(notification),行为取决于外来的突发事件,是事件驱动的,符合事件驱动式编程(Event-Driven Prog ...
- jQuery 事件绑定 和 JavaScript 原生事件绑定
总结一下:jQuery 事件绑定 和 JavaScript 原生事件绑定 及 区别 jQuery 事件绑定 jQuery 中提供了四种事件监听绑定方式,分别是 bind.live.delegate.o ...
- js事件绑定的几种方式
在JavaScript中,有三种常用的绑定事件的方法: 在DOM元素中直接绑定: 在JavaScript代码中绑定: 绑定事件监听函数 一. 在DOM元素中直接绑定 这里的DOM元素,可以理解为HTM ...
- 事件绑定addEventListener
通过addEventListener监听函数实现的dom事件绑定 addEventListener可以为当前dom添加一个事件(这个事件可以是个已有的事件),这就无法避免我们在写代码的时候重复去绑定同 ...
- 原生JS事件绑定方法以及jQuery绑定事件方法bind、live、on、delegate的区别
一.原生JS事件绑定方法: 1.通过HTML属性进行事件处理函数的绑定如: <a href="#" onclick="f()"> 2.通过JavaS ...
- Dojo初探之5:dojo的request(请求)操作、请求过程事件绑定和隐藏数据data()操作(基于dojo1.11.2版本)
前言: 上一章详细阐述了dojo的事件绑定操作,本章将讲解dojo的请求操作 注:dojo的请求操作与js和jquery完全不同! 1.dojo的请求 dojo通过request.get()/.put ...
随机推荐
- Xamarin改变移动开发的五个理由
企业开发者不能简单的抛弃现有的桌面和Web应用,然而又不得不忙着创建各种各样的应用,没有太多的预算来开发移动版本,尤其是原生版本. 采用Xamarin,C#开发人员可以使用一份基础代码创建桌面版和移动 ...
- Matcher类的简单使用
今天工作时遇到一个问题, 用正则处理html标签时不知该如何下手.还好有Matcher帮助解决了问题. 需求如下: 例如有如下html文章内容: <p><a href="w ...
- 如何在原生微信小程序中实现数据双向绑定
官网:https://qiu8310.github.io/minapp/ 作者:Mora 在原生小程序开发中,数据流是单向的,无法双向绑定,但是要实现双向绑定的功能还是蛮简单的! 下文要讲的是小程序框 ...
- 永久开启完整版Google Play
中国内地使用Play商店只能看见两个项目,即应用和游戏,但实际上有六个,见图.解决方法,第一,通过fqrouter2进入Play商店,见图,第二,通过google wallet. 参考网址:http: ...
- 关于del命令
del命令用于删除具体的文件,但是删除文件的时候如果不指定文件的扩展名就会显示找不到文件 还有如果所要删除文件的文件名中含有空格的话该命令会自动识别为几个文件,就从空格处把文件 分成几份,然后就会显示 ...
- Pandas与Matplotlib基础
pandas是Python中开源的,高性能的用于数据分析的库.其中包含了很多可用的数据结构及功能,各种结构支持相互转换,并且支持读取.保存数据.结合matplotlib库,可以将数据已图表的形式可视化 ...
- 在CentOS7中安装.Net Core2.0 SDK
1.sudo yum install libunwind libicu(安装libicu依赖) 2.curl -sSL -o dotnet.tar.gz https://go.microsoft.co ...
- linux --> 进程和线程
进程和线程 进程(process)和线程(thread)是操作系统的基本概念,下面用一个类比,来解释它们. 1. 计算机的核心是CPU,它承担了所有的计算任务.它就像一座工厂,时刻在运行. 2. 假定 ...
- 测试驱动开发实践3————testSave之新增用户
内容指引 1.确定新增用户的业务规则 2.根据业务规则设计测试用例 3.为测试用例赋值并驱动开发 一.确定新增用户的规则 1.注册用户允许通过"用户名+密码"."手机号+ ...
- 关于HTML使用ComDlg ActiveX 无法弹出相应对话框的问题1
最近发现,开发的Web应用在客户的某些IE(8,9,11)中弹出不了Windows的字体对话框. 通过 F12 跟踪,错误代码是“-2146827850”,错误信息是“ 对象不支持ShowFont属性 ...