DOM事件模型

在0级DOM事件模型中,它只是简单的执行你为它绑定的事件,比如你为某个元素添加了一个onclick事件,当事件触发时,它只是去调用我们绑定的那个方法,不再做其他的操作。

在2级DOM事件模型中,就比较复杂一些,它将不再是单纯的调用一下自身绑定的事件就完事了,它还拥有机会去处理它的祖先节点,在DOM2级事件模型中,它有一个事件传播过程,分为3个阶段,从“事件捕获”Document开始来到“目标节点”再从“目标节点”冒泡回Document对象,举段代码

  <div id="div"><a href="javascript:;">DOM事件模型</a></div><script>var div = document.getElementById("div");var a = div.children[0];document.onclick = function(){console.log("document");};a.onclick = function(){console.log("a");};div.onclick = function(){console.log("div");};</script>

可以看到我只是点击了a元素,但是div和document绑定的事件也被触发了,这就是DOM2级和1级的区别,同时你也看到,它是先输出的a,而不是div和document,虽然说它有3个阶段,但浏览器默认是在冒泡阶段才执行的,如果不这样的话,我们点击a元素就会执行多次啦。

如果你想让浏览器在捕获阶段执行,那么就不能直接使用onclick添加事件了,而是要使用addEventListener添加事件,它的第三个参数就是用来设置在哪个阶段执行,具体可以看 http://www.runoob.com/jsref/met-element-addeventlistener.html

currentTarget

event.currentTarget获取到的是当前绑定事件的那个对象,也因为此原因,他获取到的常常和this一样,下面是一个示例:

  <a href="javascript:;" id="a">evnet.currentTarget</a><script>var a = document.getElementById("a");a.onclick = function(event){console.log("this:",this);console.log("currentTarget:",event.currentTarget);};</script>

当我点击a标签时,this和currentTarget打印出来的都是a标签本身,如下图

既然如此这个currentTarget有啥用呢,这是一开始的想法,但随后发现不对,想到这个currentTarget始终获取到的是那个绑定事件的对象,但this却有很大的不同,因为this并不关心是谁绑定的它,它只关心是谁执行的它,因此如果再将上面那段代码改造改造,我们就会发现,它们真的是不一样的,代码如下:

var a = document.getElementById("a");a.onclick = function(event){(function(){console.log("this:",this);console.log("currentTarget:",event.currentTarget);}());};

效果如图

这也就是说,某些时候如果不能通过this来获取绑定事件的对象时,就可以使用event.currentTarget。

有些人认为event.currentTarget就是this,其实不然,容易把event.currentTarget当成this,主要原因就是,在事件处理器中,我们常常使用的是this,而不是event.currentTarget,至于为什么,反正我是因为从接触js开始,所看过的教程上都是那么用的,时间长了,竟然忘了一件事,event.currentTarget才是真的属于事件处理器的,而this不过是个冒牌货。

target

event.target获取到的是触发事件的那个元素。

网上常说的事件委派,就是通过event.target来实现的,所谓的事件委派,就是我并不给某个具体的东西添加事件,而通过给它的父辈添加事件,当我点击那个具体的元素时,父辈的事件会触发(因为有事件冒泡),而这时就需要用到evnet.target了,因为在父辈的事件中this并不指向当前点击的那个元素,但是event.target可以获取到是谁触发的当前事件。以下是一个示例

  <ul id="ul"><li>111</li><li>222</li><li>333</li></ul><script>var ul = document.getElementById("ul");ul.onclick = function(event){console.log(event.target);};</script>

当我点击第二个li时,输出如下值

当然我们也可以直接给这三个li添加事件,但是那样的话就绑定了3次事件,如果有1万个元素,就绑定了1万次,而通过事件委派则只需要绑定一次。

最主要倒也不是说不能给li添加事件,而是如果这些li并不是事先添加的,而是通过后端返回的数据,再渲染的,那么要是我们再放回数据之前就给li添加事件,那么就会有问题,因为根本就不存在li元素,也就是说后添加的元素无法事先去添加事件,比如下面这段代码就有些问题。

  <ul id="ul"><li>1111</li></ul><script>var ul = document.getElementById("ul");var lis = ul.children;for(var i=0;i<lis.length;i++){lis[i].onclick = function(){console.log(this);};}var li = document.createElement("li");li.innerText = "2222";ul.appendChild(li);</script>

当我点击第二个li时,什么都没有输出,如下图

因为第二个li是在for循环以后添加的,所有并没有给第二个li添加上事件。而如果是给ui添加事件,那就不一样了,代码如下

  <ul id="ul"><li>1111</li></ul><script>var ul = document.getElementById("ul");ul.onclick = function(event){console.log(event.target);};var li = document.createElement("li");li.innerText = "2222";ul.appendChild(li);</script>

不管我点击第几个li都可以正常的输出,如下图

不过因为event.target获取到的是最终触发这个事件的元素,所以在写代码的时候,我们经常需要加上判断,因为通过event.target获取到的不一定是我们想要的元素,比如下面这个例子

  <ul id="ul"><li><em>111</em></li></ul><script>var ul = document.getElementById("ul");ul.onclick = function(event){console.log(event.target);};</script>

当我点击111的时候,获取到的是em标签,如下图

但我想要的是li,因此我们就得加上判断,我经常使用的一招就是,通过判断元素的标签名,代码如下

  <ul id="ul"><li><em>111</em></li></ul><script>var ul = document.getElementById("ul");ul.onclick = function(event){var target = event.target;if(!(target.tagName.toLowerCase()==="li")){target = target.parentNode;}if(target.tagName.toLowerCase()==="li"){console.log(target);}};</script>

tagName可以获取到元素名,但是每个浏览器获取到的都有可能不同,有些浏览器获取到的是大写的标签名,有些浏览器获取到的是小写的标签名,因此在上面那段代码中,将标签名都转换成小写的,通过判断标签名来确定是不是我要的元素。

虽然这种判断可行,但仔细想想也能想到,这个方法,也是有缺陷的,如果DOM比较复杂,则容易判断错误,目前还没有想到更好的方法。

记住正是因为有了事件捕获和事件冒泡才有了event.target的用武之处。

relatedTarget

在event中有一个relatedTarget属性,它可以获取到和它相关的元素(通过谁来到这个元素上的,要到哪个元素上去),举个例子

  <div id="box"><p>新的起点,新的梦想。</p></div><script>var box = document.getElementById("box");box.onmouseout = function(event){console.log(event.relatedTarget);};</script>

在onmouseout中relatedTarget可以获取到它要到哪个元素上去,相反在onmouseover中relatedTarget获取到的是从哪个元素来的,代码如下

  <div id="box"><p>新的起点,新的梦想。</p></div><script>var box = document.getElementById("box");box.onmouseover = function(event){console.log(event.relatedTarget);};</script>

可以看到当我从html移入到div上时,relatedTarget获取到的是html,也就是它从html来到div的。

想起一句话:我从哪里来,又要到哪里去。

当第一次看到这个属性的时候,给我的感觉是,它肯定是很有用的,事实上也确实有些用处,如果细心的朋友,看上面的那个动画图,会发现一件事,onmouseover和onmouseout存在一个问题,离开或进入它的子元素事件也会被触发。大多数情况我们是不希望这样的,因此如果使用onmouseover或onmouseout时,最好判断一下,是否真的移出了盒子。

在元素中有一个contains方法,可以用来判断某个元素是否是它的子元素,如果是返回true,否则返回false,而以上问题我们就可以通过这个方法来写,代码如下

  <div id="box"><p>1111111<em>新的起点,新的梦想。</em></p></div><script>var box = document.getElementById("box");box.onmouseout = function(event){if(!this.contains(event.relatedTarget)){console.log(this);}};</script>

如果你只是想解决以上这个问题,那么大可不必这样写,因为在浏览器中,分别有两个和它们相同的事件,但它们并没有这个问题,分别是onmouseenter鼠标移入事件和onmouseleave鼠标移出事件。

需要注意的是relatedTarget属性只对onmouseout和onmouseover事件有用,虽然对onmouseenter和onmouseleave事件也有用,不过很少有人会那么去用,因为我发现relatedTarget属性除了用在解决上面那个问题以外,还真没发现有什么其他的用处。

注意点

需要注意一点,在普通函数中是不存在event对象的,只有在事件中才有,比如这么这段代码,如果使用event就会输出undefined。

(function(event){console.log(event); //undefined
})();

自定义事件

官方提供了一些如onclick、onmouseover、onscroll等事件给我们使用,但难免也会有自己建立事件的需求,比如监听某个变量的变化,虽然听起来好像不太可能,但方法总是有的,我们不让使用者直接操作某个变量,而是提供一个方法给他操作,下面是一段实现思路。

  <script>var Foo = (function(){var a = 10;return {get:function(){return a;},set:function(value){if(a!==value){a = value;this.change();}},change:function(){console.log("a的值有变化");}};})();Foo.set(9);Foo.set(52);</script>

以上我将变量a封死在函数作用域里面,让外部无法直接操作变量a,要操作就只能通过调用我事先设置的set方法,之所以要这样弄是因为我们是无法知道变量是什么时候改变了的,而如果让使用者操作我们提供事先提供的方法,那么我们就可以对其进行处理了。

以上并不是一个自定义事件,如果想要实现自定义方法,我们可以通过javascript提供的3个方法来弄,分别是document.createEvent()、event.initEvent()、element.dispatchEvent()。

  • createEvent用来创建一个新的事件
  • initEvent用来初始化事件
  • dispatchEvent用来触发事件

具体可以看 http://www.w3school.com.cn/xmldom/met_event_initevent.asp

实现如下

  <script>var ev = document.createEvent("HTMLEvents");ev.initEvent("changeA",false,false);var Foo = (function(){var a = 10;return {get:function(){return a;},set:function(value){if(a!==value){a = value;document.dispatchEvent(ev);}}};})();document.addEventListener("changeA",function(){console.log("a有变化",Foo.get());});Foo.set(555);Foo.set(520);</script>

以上也就是将set中的change方法改成dispatchEvent,用来触发changeA事件,如果你想要解绑这个事件,和你给onclick事件解绑是一样的。

IE attachEvent之坑

当我们通过attachEvent添加事件时,需要注意一件事,我们为它添加的事件函数,IE并没有将这个函数作为元素的方法调用,而是作为全局函数来调用,因此,它里面的this并不指向当前绑定的事件对象,而是window,并且event也不指向当前事件对象,看下面这段代码

  <a href="javascript:;" id="a">addEventListener</a><script>var a = document.getElementById("a");a.attachEvent("onclick",function(){console.log("this:",this);console.log("currentTarget:",event.currentTarget);});</script>

当我点击a标签时,输出如下:

转载于:https://www.cnblogs.com/pssp/p/6382874.html

走进javascript——DOM事件相关推荐

  1. html鼠标离开点击停留,Javascript DOM事件操作小结(监听鼠标点击、释放,悬停、离开等)...

    本文实例总结了Javascript DOM事件操作.分享给大家供大家参考,具体如下: 使用JavaScript可以对HTML页面上的各种事件进行监听,如鼠标点击/释放,鼠标悬停/离开,等等. 效果图: ...

  2. JavaScript Dom 事件 Bom 定时器方法

    目录   Dom HTML Dom Node:节点对象,其他5个的父对象 修改标签体内容 属性 innerHTML   事件   BOM 定时器方法 Navigator:浏览器对象 creen:显示器 ...

  3. javascript DOM事件总结

    1 <html> 2 <title>事件</title> 3 <meta charset="utf-8"/> 4 <body& ...

  4. 从八道面试题看JavaScript DOM事件机制

    原文:https://segmentfault.com/a/1190000013894510#articleHeader0 As we all know,事件机制其实很简单,无非冒泡和捕获 这两点,笔 ...

  5. javaScript的使用(5)DOM事件

    dom事件 浏览器监听特定的条件或用户行为,并且触发相应的操作(函数) 常见的dom事件如下: onclick:单击事件 onfocus:焦点事件 onblur:失去焦点事件 onkeydown:键盘 ...

  6. javascript中0级DOM和2级DOM事件模型浅析

    Javascript程序使用的是事件驱动的设计模式,为一个元素添加事件监听函数,当这个元素的相应事件被触发那么其添加的事件监听函数就被调用: <input type="button&q ...

  7. javascript原生事件句柄、BOM、DOM对象属性方法总结

    javascript原生事件句柄.BOM.DOM对象属性方法总结 JS事件句柄 事件句柄 类型 说明 onabort 事件句柄 图像加载被中断 onblur 事件句柄 元素失去焦点 onfocus 事 ...

  8. ajax php 观察者模式,JavaScript观察者模式定义和dom事件实例详解

    观察者模式(发布-订阅模式):其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript中,一般使用事件模型来替代传统的观察者模式. 好处: ...

  9. JavaScript(六)—— DOM 事件高级

    本篇为 JavaScript 系列笔记第六篇,将陆续更新后续内容.参考:黑马程序员JavaScript核心教程,前端基础教程 系列笔记: JavaScript(一)-- 初识JavaScript / ...

  10. 前端JavaScript之DOM事件操作~都是干货

    下面是对DOM操作事件的整理,希望可以帮助到有需要的小伙伴~ 文章目录 DOM事件操作 JavaScript的基础 事件 代码书写步骤 1.获取绑定事件的元素 2.绑定事件 3.编写事件 注意事项 D ...

最新文章

  1. 报错——StackOverflowError
  2. MFC中实现模态对话框的结构与原理
  3. java星座查询系统_星座查询示例代码
  4. 一文读懂 | CPU负载均衡实现
  5. python使方法执行10次_Python提升程序性能的七个手段
  6. mysql更新id最大_我们可以在单个MySQL查询中更新具有最高ID的行吗?
  7. php 日期时间操作-可算出几天后的时间
  8. [转]Java实现定时任务的三种方法
  9. i美股投资研报--Michael Kors(IPO版) _Michael Kors(KORS) _i美股
  10. python 点云配准_点云的全局配准
  11. html 随机抽奖,随机抽奖页面js
  12. imple introduction to LDD
  13. 体系结构14_控制相关的动态解决技术
  14. 简单拖拉拽就能做数据可视化分析图表
  15. note 8 字符串
  16. IDEA中suppress warnings
  17. vue简单实现词云图组件
  18. 机器学习——变分推断
  19. 基于Java的Minecraft游戏后端自定义插件 05事件监听器
  20. 写一下拼多多签到的1天,2天....30天的测试用例?其中签到5天可以可以领现金,签到30天可以获得购物卷,断签需要从第一天开始重新签?

热门文章

  1. MySQL完全自学手册
  2. Java线程的5种状态及切换(透彻讲解)-京东面试
  3. Linux登陆密码策略
  4. 用CSS制作细线表格
  5. 《机器人编程实战》一一2.1 为什么需要更多努力
  6. React-Native入门指南——第七篇动手写组件
  7. [转载]修改SDE权限造成无法在ArcMap中绘制图形的解决办法
  8. Linux学习之十一、环境变量的功能
  9. bgr to rgb
  10. \r\n的来历与用法