终于学到事件了,不知道为何听到“事件”就有一种莫名的兴奋。可能是之前的那些知识点过于枯燥无味吧,说起事件感觉顿时高大上了。今天我们就来好好分析下这个高大上的东西。

可以说,如果没有事件我们的页面就只能阅读了。有了事件,我们可以通过键盘或是鼠标和页面交互了,通过我们不同的操作页面给出不同的响应。好了,开始我们今天的分析吧。

DOM0级事件处理方式

什么是DOM0级?

其实世上本来没有DOM0级,叫的人多了就有了DOM0级。

在1998 年 10 月 DOM1级规范成为 W3C 的推荐标准,在此之前的实现我们就习惯称为DOM0级,其实本是没有这个标准的。

<input type="button" value="but" id="but" />
<script type="text/javascript">
document.getElementById("but").onclick = function () {
alert("点击了按钮1");
}
document.getElementById("but").onclick = function () {
alert("点击了按钮2");
}
</script>

上面代码,我们发现点击按钮时,仅仅只弹出了“点击了按钮2”。上一个定义的方法被覆盖了。这种会覆盖上一次事件定义的方式我们称为DOM0级事件。

如果我们使用Jquery来添加事件的话:

<script src="../Scripts/jquery-1.8.2.js"></script>
<input type="button" value="but" id="but" />
<script type="text/javascript">
$("#but").click(function () {
alert("点击了按钮1");
});
$("#but").click(function () {
alert("点击了按钮2");
});

我们会发现依次弹出了“点击了按钮1”,“点击了按钮2”,这是怎么做到的?为什么没有覆盖上一次的定义,我猜应该是使用到了DOM2级事件机制。(我没有看过Jquery的源码,暂时还看不懂)。

DOM2级事件处理方式

<input type="button" value="but" id="but" />
<script type="text/javascript">
document.getElementById("but").addEventListener("click", function () {
alert("点击了按钮1");
});
document.getElementById("but").addEventListener("click", function () {
alert("点击了按钮2");
});
</script>

如此通过元素对象的addEventListener添加的方法就是2级事件。这里需要注意,与0级事件不同的是事件名前面不能带“on”了。点击按钮弹出的结果和前面的Jquery添加方式一样。

有人可能要问了,怎么没有DOM1级事件。我能说的是没有就是没有,没有为什么。在确定DOM1级标准的时候不需要扩展事件定义机制,DOM0级的事件就够用了。

我们刚才通过2级事件添加了方法,那么如果我们想要删除其中的一个怎么办。如果是上面的那种匿名方法,我可以很明确的告诉你没办法移除。下面我们来说说可以移除的添加方式吧:

<input type="button" value="but" id="but" />
<script type="text/javascript">
document.getElementById("but").addEventListener("click", fun1);//给click事件添加方法fun1
document.getElementById("but").addEventListener("click", fun2);//给click事件添加方法fun2 function fun1() {
alert("点击了按钮1");
}
function fun2() {
alert("点击了按钮2");
} document.getElementById("but").removeEventListener("click", fun1);//给click事件移除方法fun1
</script>

如此就通过removeEventListener方法进行移除操作了。

以上只是DOM2级的标准实现,当然除了IE这个怪胎非得当搅屎棍。在IE下,有同效的实现函数:

<input type="button" value="but" id="but" />
<script type="text/javascript">
document.getElementById("but").attachEvent("onclick", fun1, false);//给click事件添加方法fun1
document.getElementById("but").attachEvent("onclick", fun2, false);//给click事件添加方法fun2 function fun1() {
alert("点击了按钮1");
}
function fun2() {
alert("点击了按钮2");
} document.getElementById("but").detachEvent("onclick", fun1);//给click事件移除方法fun1

注意:attachEvent() 和 detachEvent() 替换了addEventListener()和removeEventListener(),且第一个参数是事件名前面加了"on"。

DOM3级事件

可能有人觉得很奇怪,哪来的DOM3级事件啊。其实上面我们说的DOM0级和DOM2级事件说的是事件的处理方式而已,而这里说的DOM3级事件是说的在DOM3级中新增的一些事件。

至于DOM1级事件,那我就真的没听过。

DOM3级事件是在DOM2级事件的基础上重新定义了或是新增了某些事件。如鼠标事件:

DOM2有,click、mousedown、mousemove、mouseout、mouseover、mouseup
而DOM3级中却有,click、dblclick、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup

(其中dblclick、mouseenter、mouseleave是DOM3中新增的)
DOM3级事件实现方式可以用DOM0和DOM2级中的方式,只是新增了写事件类型。这里就不一一列举了。

事件冒泡

什么是事件冒泡?我们先来看个例子。

<div onclick="divfun();" style="border:1px dashed red;padding:50px">
<span onclick="spanfun();" style="border: 1px dashed #00ff21; padding: 30px; ">
<input type="button" value="but" onclick="butfun();" style="border: 1px dashed #0094ff" />
</span>
</div>
<script type="text/javascript">
function butfun() {
alert("按钮被点击了");
}
function spanfun() {
alert("span被点击了");
}
function divfun() {
alert("div被点击了");
}
</script>

一个div包了一个span,然后span里面包了一个button。我们在点击按钮的时候会先触发按钮事件,然后触发span的点击事件,然后触发div的点击事件。这就是事件冒泡。(使用DOM0级事件默认是事件冒泡方式)

效果图:

示意图:

事件捕获

什么是事件捕获?其实就是事件冒泡的逆向。

那我们怎么实现这个效果呢?我们可以通过DOM2级事件。上面我们已经简单的讲解过了DOM2级事件的实现方式

通过addEventListener和removeEventListener给事件添加和删除函数。上面我们讲addEventListener的时候如果你再回头看看,我们只给了两个参数,第一个是事件名,第二个是要添加的方法,其实还有第三个参数一个布尔值用来表示事件流方向(true为事件捕获方向,false为事件冒泡方向)。那么我们完全可以通过DOM2级事件来实现事件捕获的效果,如:

<div id="mydiv" style="border:1px dashed red;padding:50px">
<span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
<input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
</span>
</div>
<script type="text/javascript">
document.getElementById("mydiv").addEventListener("click", divfun, true);
document.getElementById("mysapn").addEventListener("click", spanfun, true);
document.getElementById("mybut").addEventListener("click", butfun, true); function butfun() {
alert("按钮被点击了");
}
function spanfun() {
alert("span被点击了");
}
function divfun() {
alert("div被点击了");
}
</script>

效果图:

同样,我们也可以通过DOM2级事件实现事件冒泡,就上面的代码仅仅只需要把addEventListener的第三那个参数改成false就可以了,有兴趣的同学可以自己试试。

然后IE这个搅屎棍又开始不服了,我就不实现事件捕获你能把我怎么着。IE中等效实现的attachEvent的根本就没给第三个参数,所以为了兼容,我们一般只用事件冒泡(IE只支持事件冒泡)。

事件冒泡的使用

  • 取消事件冒泡

通过上面,我们知道只要点击了按钮,那么按钮的上层元素中的点击事件都会触发。那我们会想如果我TM就只想点击某个元素的时候才 触发,不想让它往上冒怎么办,请看下面:

<div id="mydiv" style="border:1px dashed red;padding:50px">
<span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
<input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
</span>
</div>
<script type="text/javascript">
//第三个参数是false,那么就是事件冒泡了
document.getElementById("mydiv").addEventListener("click", divfun, false);
document.getElementById("mysapn").addEventListener("click", spanfun, false);
document.getElementById("mybut").addEventListener("click", butfun, false); function butfun(event) {
event.stopPropagation();//在点击按钮时,取消事件冒泡
alert("按钮被点击了");
}
function spanfun() {
//这里没有取消事件冒泡,所以点击span的时候还是会继续冒泡到div
alert("span被点击了");
}
function divfun() {
alert("div被点击了");
}
</script>

效果图:

您如果仔细看了效果图,那么你会发现。点击按钮的时候并没有冒泡,而点击span的时候还是冒泡了。那是因为我们代码里面在按钮事件的方法里面加了 event.stopPropagation()//取消冒泡 。

  • 事件委托

既然可以如此,我们可以在每个事件方法里面都加上取消冒泡,那么所有的元素都只实现自己的事件对应的方法了。我们发现这个事件冒泡反而把事情搞麻烦了,好好的一个元素对应一个事件干嘛要冒泡啊,还要手动去取消冒泡。既然有这个东西,它总是有它的作用的。我们看到上面我们定义事件方法时,取到了每个元素,然后给每个元素定义方法。那我们可以通过事件冒泡定义一个方法来实现吗,先看看下面的代码:

<div id="mydiv" style="border:1px dashed red;padding:50px">
<span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
<input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
</span>
</div>
<script type="text/javascript">
//第三个参数是false,那么就是事件冒泡了
document.getElementById("mydiv").addEventListener("click", divfun, false); function divfun(event) {
var targetID = event.target.id
if (targetID == "mybut") {
alert("按钮被点击了");
} else if (targetID == "mysapn") {
alert("span被点击了");
} else if (targetID == "mydiv") {
alert("div被点击了");
}
}
</script>

效果图:

仔细观察的你,会发现我们点击每个元素会触发对应消息。这就是我们上面为每个元素添加方法然后取消冒泡同样的效果。那么我们再来分析下实现代码,会发现这里反而是使用了冒泡。

event.target//返回事件的目标节点(触发该事件的节点)  var targetID = event.target.id //返回事件的目标节点的id(触发该事件的节点的Id)

因为我们为最外面的div添加了事件的方法,所以我们在点击按钮的时候会依次触发按钮、span、div的点击事件,然按钮和span都没有定义事件方法,所以不管是点击按钮、span还是div都会冒泡到div的点击事件,然后我们就可以根据上面的target属性来得知到底是由那个节点触发的。请看示意图:

有人会这,这么麻烦有什么好处呢?我们仔细看看这个通过冒泡实现的个节点点击事件,你有没有发现我们仅仅只是通过getElementById取了一个最外层的div元素,且我们也仅仅只用了一个方法(虽然方法里面的逻辑会更加复杂点)。这只是3个元素,如果有30个呢?甚至上百个呢?我们只定义最外层的元素,这样就减少了大量的DOM引用了(这样就直接减少了检索元素需要花的时间),同时也可以减少内存的占用。直接提升了性能。(虽然很多时候我们不会这样来定义事件,我自己就很少这样来定义事件,可能是习惯问题吧。>_<)

这是学习记录,不是教程。文中错误难免,您可以指出错误,但请不要言辞刻薄。

原文首链:http://www.haojima.net/zhaopei/531.html

本文已同步至目录索引:一步步学习javascript

一步步学习javascript基础篇(8):细说事件的更多相关文章

  1. 一步步学习javascript基础篇(0):开篇索引

    索引: 一步步学习javascript基础篇(1):基本概念 一步步学习javascript基础篇(2):作用域和作用域链 一步步学习javascript基础篇(3):Object.Function等 ...

  2. 一步步学习javascript基础篇(3):Object、Function等引用类型

    我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂 ...

  3. 一步步学习javascript基础篇(7):BOM和DOM

    一.什么是BOM.什么是DOM BOM即浏览器对象模型,主要用了访问一些和网页无关的浏览器功能.如:window.location.navigator.screen.history等对象. DOM即文 ...

  4. 一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)

    上一篇介绍了对象创建的几种基本方式,今天我们看分析下对象的继承. 一.原型链继承 1.通过设置prototype指向“父类”的实例来实现继承. function Obj1() { this.name1 ...

  5. 一步步学习javascript基础篇(4):面向对象设计之创建对象(工厂、原型和构造函数等模式)

    前面我们介绍了可以通过Object构造函数或对象字面量都可以用来创建单个对象,但是如果需要创建多个对象的话,显然很多冗余代码. 接下来介绍几种模式来创建对象.不过在此之前,我们还是先来了解下 type ...

  6. 一步步学习javascript基础篇(1):基本概念

    一.数据类型 数据类型 基本数据类型(五种) Undefined Null Boolean Number String 复杂数据类型(一种) Object Undefined:只有一个值undefin ...

  7. 一步步学习javascript基础篇(6):函数表达式之【闭包】

    回顾前面介绍过的三种定义函数方式 1. function sum (num1, num2) { return num1 + num2; }  //函数声明语法定义 2. var sum = funct ...

  8. 一步步学习javascript基础篇(2):作用域和作用域链

    作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = & ...

  9. 一步步学习javascript基础篇(9):ajax请求的回退

    需求1: ajax异步请求 url标识请求参数(也就是说复制url在新页面打开也会是ajax后的效果) ajax异步请求没问题,问题一般出在刷新url后请求的数据没了,这就是因为url没有记录参数.如 ...

随机推荐

  1. C# ini文件操作【源码下载】

    介绍C#如何对ini文件进行读写操作,C#可以通过调用[kernel32.dll]文件中的 WritePrivateProfileString()和GetPrivateProfileString()函 ...

  2. wepack+sass+vue 入门教程(一)

    一.安装node.js node.js是基础,必须先安装.而且最新版的node.js,已经集成了npm. 下载地址 node安装,一路按默认即可. 二.全局安装webpack npm install ...

  3. iOS开源项目周报0105

    由OpenDigg 出品的iOS开源项目周报第四期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开发方面的开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. He ...

  4. 由Dapper QueryMultiple 返回数据的问题得出==》Dapper QueryMultiple并不会帮我们识别多个返回值的顺序

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#dapper 今天帮群友整理Dapper基础教程的时候手脚快了点,然后遇到了一个小问题,Dapp ...

  5. JavaScript的继承实现方式

    1.使用call或apply方法,将父对象的构造函数绑定在子对象上 function A(){ this.name = 'json'; } function B(){ A.call(this); } ...

  6. 一起学微软Power BI系列-使用技巧(3)Power BI安卓手机版安装与体验

    Power BI有手机版,目前支持安卓,苹果和WP,不过没有WP手机,苹果在国内还不能用,要FQ和用就不测试了.安卓的我也也是费了九牛二虎之力才把app下载下来,把方法分享给大家. FQ太麻烦,所以建 ...

  7. 使用SecureCRT连接虚拟机(ubuntu)配置记录

    这种配置方法,可以非常方便的操作虚拟机里的Linux系统,且让VMware在后台运行,因为有时候我直接在虚拟机里操作会稍微卡顿,或者切换速度不理想,使用该方法亲测本机效果确实ok,特此记录. Secu ...

  8. PayPal高级工程总监:读完这100篇论文 就能成大数据高手(附论文下载)

    100 open source Big Data architecture papers for data professionals. 读完这100篇论文 就能成大数据高手 作者 白宁超 2016年 ...

  9. 在centos7上安装ClamAV杀毒,并杀毒(centos随机英文10字母)成功

    前言 上传文件的时候发现总是失败,查看top发现有个进程一直cpu占用80%以上,而且名称还是随机数.kill之后,一会儿又重新生成了.突然发现居然没有在服务端杀毒的经历.在此处补齐. 安装clama ...

  10. iOS架构一个中型普通App的一些经验总结

    这一版比较完善的的App终于提交审核了.有时间写写自己的一些经验的总结了.自己主导的从0到比较成型的app到目前来说也只有两个,但是其中的很多东西都是大同小异.基本上是想到了什么就写什么,感觉写的不到 ...