事 件

1.事件流

事件流描述的是从页面中接收事件的顺序。
有两种,分别是:事件冒泡流和事件捕获流

  1. 事件冒泡
    IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

  2. 事件捕获(event capturing)
    事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。
    事件捕获从IE9和现在浏览器才支持他,也就是说支持DOM2事件的浏览器才支持他

  3. DOM事件流
    “DOM2级事件”规定的事件流包括3各阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。


    dom事件流模拟图

在 DOM 事件流中,实际的目标( <div> 元素)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从 document 到 <html> 再到 <body> 后就停止了。下一个阶段是“处于目标”阶段,于是事件在 <div>上发生,并在事件处理(后面将会讨论这个概念)中被看成冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回文档。(这里的事件在div上发生,并在事件处理中被看成冒泡阶段的一部分可以这么理解:在“处于目标”阶段,事件处理程序就开始执行了,那么在事件处理程序里面不是有阻止事件冒泡嘛,你要阻止那么就必须有冒泡开始啊,那就把处于目标阶段看成是事件冒泡的一部分,当然只是在事件处理程序里面这么认为,事件流还是分三个阶段。

2.事件处理程序

  1. HTML 事件处理程序
    行内式
<input type='button' value='click me' onclick='alert("haha")' >
  1. DOM0级事件处理程序
    给元素添加自己的事件处理程序属性。这些属性通常全部小写,比如onclick。
var btn = document.getElementById("mybtn");

btn.onclick = function(){
      //事件处理程序的函数部分
      // this引用当前元素,即btn
}

以这种方式被添加的事件处理程序在事件流的冒泡阶段被处理。也可以删除通过DOM0级方法指定的事件处理程序,只要向下面这样将事件处理程序属性的值设为null即可:

btn.onclick = null;

如果你是用的是html指定事件处理程序,那么onclick属性的值就是一个包含着在同名html特性中指定的代码的函数。而将相应的属性设置为null,也可以删除以这种方式指定的事件处理程序。(这个就是说行内式绑定事件处理程序相当于dom0级方法指定的事件处理程序,可以用dom0级的方法去获取或换行内式绑定的同名事件的处理程序)。

  1. DOM2级事件处理程序
    两个方法:addEventListener(),removeEventListener()。
    所有的DOM节点都包含这两个方法,他们都接受三个参数:要处理的事件名(没有on哦比如click)、作为事件处理程序的函数和一个布尔值。这个布尔值如果是true,表示在事件捕获阶段调用这个事件处理程序,如果是false,表示在冒泡阶段调用事件处理程序。
    DOM2级事件处理程序的主要好处是可以添加多个事件处理程序。
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
    alert(this.id);
}, false);
btn.addEventListener("click", function(){
    alert("Hello world!");
}, false);

这两个事件处理程序会按照添加他们的顺序触发。先显示元素的ID,再显示“hello world!”消息。
通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除。在给removeEventListener()传第二个参数的时候,必须传入事件处理函数的函数名,不能写一个内容一样的匿名函数代替,那样是不对的,因为那两个函数是完全不同的函数。
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。

  1. IE事件处理程序
    两个方法:attachEvent()和detachEvent。
    接收两个参数:事件处理程序名称(有on哦比如'onclick')与事件处理程序函数。由于IE8及跟早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。
    在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域。在使用DOM0级方法的时候,事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});

在编写跨浏览器的代码时,牢记这一区别非常重要。
与 addEventListener() 类似, attachEvent() 方法也可以用来为一个元素添加多个事件处理程序。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
btn.attachEvent("onclick", function(){
alert("Hello world!");
});

这里调用了两次 attachEvent() ,为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是 "Hello world!" ,然后才是 "Clicked" 。
使用 attachEvent() 添加的事件可以通过 detachEvent() 来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同函数的引用传给 detachEvent() ,就可以移除相应的事件处理程序。

var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
btn.attachEvent("onclick", handler);
// 这里省略了其他代码
btn.detachEvent("onclick", handler);

支持IE事件处理程序的浏览器只有IE和Opera。

  1. 跨浏览器的事件处理程序
var EventUtil = {
addHandler: function(element, type, handler){
    if (element.addEventListener){
              element.addEventListener(type, handler, false);
    } else if (element.attachEvent){
              element.attachEvent("on" + type, handler);
    } else {
              element["on" + type] = handler;
     }
},
removeHandler: function(element, type, handler){
      if (element.removeEventListener){
                  element.removeEventListener(type, handler, false);
       } else if (element.detachEvent){
                 element.detachEvent("on" + type, handler);
        } else {
                  element["on" + type] = null;
        }
}
};

事件对象

事件对象存在于事件处理程序函数中,event对象可以使函数的第一个形参,也是window对象的属性。所以在通过HTML特性指定事件处理程序时,变量event未经申明就可以使用,因为他保存着event对象,event是window对象的属性。

事件对象的属性与方法

事件对象的属性与方法.png

this, currentTarget, target分别指的是什么?他们的关系是什么?

在事件处理程序内部,对象this始终等于currentTarget的值,即事件绑定的那个对象,而target则只包含时间的实际目标。看个例子。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.currentTarget === this); //true
alert(event.target === this); //true
}; 

由于click事件的目标是按钮,因此这三个值是相等的。如果事件处理程序存在于按钮的父节点中(例如document.body),那么这些值是不相同的。看下面这个例子:

document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
}; 

当单击这个例子中的按钮时,this和currentTarget都等于document.body,即事件绑定的那个对象。而target则是事件最具体发生的那个对象,即按钮。(点击在按钮上的)
还有就是事件捕获只能在DOM2二级事件处理程序里存在,DOM0级和HTML里面绑定的事件都是发生在事件冒泡或者处于目标阶段。

event.type

event.type 指的是事件的类型,如点击事件,他的值就是'click'。

preventDefault()

想要阻止特定事件的默认行为,可以使用preventDefault()方法,例如阻止连接在被点击之后默认会跳转到href特性指定的URL。你可以在事件处理程序函数里面调用event.preventDefault()方法。

stopPropagation()

stopPropagation()方法用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获冒泡
看下面的这个例子:

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event){
alert("Body clicked");
};

对于这个例子而言,如果不调用 stopPropagation() ,就会在单击按钮时出现两个警告框。可是,由于 click 事件根本不会传播到 document.body ,因此就不会触发注册在这个元素上的 onclick 事件处理程序。

stopImmediatePropagation()

如果某个元素有多个相同类型事件的事件监听函数,则当该类型的事件触发时,多个事件监听函数将按照顺序依次执行.如果某个监听函数执行了 event.stopImmediatePropagation()方法,则除了该事件的冒泡行为被阻止之外(event.stopPropagation方法的作用),该元素绑定的后序相同类型事件的监听函数的执行也将被阻止。

eventPhase

事件对象的eventPhase属性可以用来确定当前事件处于事件流的哪个阶段。如果是在捕获阶段调用的事件处理程序,那么eventPhase等于1;如果事件处理程序在处于目标阶段调用,那么eventPhase等于2,如果是在冒泡阶段调用的事件处理程序,那么eventPhase等于3.这里注意一点:尽管“处于目标”发生在冒泡阶段,但eventPhase仍然一直等于2。发现没有:当事件捕获阶段和事件冒泡阶段调用事件处理程序的时候,event.target不等于this对象和currentTarget属性,而只有在eventPhase等于2的时候,这三个才相等。
当事件处理程序绑定的对象和事件发生的那个具体的对象是同一个对象的时候,那么eventPhase一定等于2,this、currentTarget、target也一定相等。就算这时候用DOM2级事件去绑定事件处理程序,并传入true,要他在事件捕获阶段调用事件处理程序,他的eventPhase值还是2,因为在DOM事件流中,实际的目标(target)在捕获阶段不会接收到事件。

只有在事件处理程序执行期间,event对象才会存在;一旦事件处理程序执行完成,event对象就会被销毁。

事件类型

  1. load
  2. unload
  3. resize
  4. scroll

客户区坐标位置

event.clientX 和event.clientY

页面坐标位置

event.pageX和event.pageY
在页面没有滚动的情况下,pageX和pageY的值与clientX和clientY相等。
在IE8及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息可以计算出来。这时需要用到 document.body (混杂模式)或 document.documentElement (标准模式)中的scrollLeft和scrollTop的属性。

屏幕坐标位置

event.screenX 和event.screenY

修改键

虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。这些修改键就是 Shift、Ctrl、Alt 和 Meta(在 Windows键盘中是 Windows键,在苹果机中是 Cmd 键),它们经常被用来修改鼠标事件的行为。DOM 为此规定了 4 个属性,表示这些修改键的状态: shiftKey 、 ctrlKey 、 altKey 和 metaKey 。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为 true ,否则值为 false 。
IE9、Firefox、Safari、Chrome和 Opera 都支持这 4 个键。IE8 及之前版本不支持metaKey 属性

相关元素

这个属性只对mouseover和mouseout事件才包含值。
这个有意思,具体可以看看高程373页。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • 一、问答 1. dom对象的innerText和innerHTML有什么区别? innerHTML: 也就是从对象...
    饥人谷_罗伟恩阅读 586评论 0 2
  • 本章内容 理解事件流 使用事件处理程序 不同的事件类型 JavaScript 与 HTML 之间的交互是通过事件实...
    闷油瓶小张阅读 277评论 0 0
  • 如何批量操作 css 如何获取 DOM 计算后的样式 使用getComputedStyle获取元素计算后的样式 实...
    _Dot912阅读 552评论 1 3
  • JavaScript 程序采用了异步事件驱动编程模型。在这种程序设计风格下,当文档、浏览器、元素或与之相关的对象发...
    劼哥stone阅读 1,250评论 3 11
  • 声明:本文来源于http://www.webzsky.com/?p=731我只是在这里作为自己的学习笔记整理一下(...
    angryyan阅读 6,945评论 1 6