事件

前言

前段时间在周会上被迫分享了一些 JavaScript 基础知识,后来听小伙伴反馈,组织性和逻辑性太乱,今天自己特意翻了下书本(JavaScript高级程序设计),以下是阅读后的整理,以便后续温故知新。

嗯,今天的主角是事件

事件

定义

以我的理解,事件就是指一系列的动作,像我们经常接触的click、dbclick以及键盘的keydown、keyup或者还有一些文档(DOM)的加载、图片的加载,焦点事件等等。其实事件的主要目的就是为了JavaScriptHTML更好的交互。

课本上的定义是:

事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间

事件流

事件流是事件中一个重要的概念,由于历史(IE与Netscape巴拉巴拉~)的原因,出现了两种完全相反的事件流概念。

首先看下事件流的定义:

事件流是描述页面接收事件的顺序

顾名思义,事件流就是指事件的流向嘛,这个很好理解。前面说两位爸爸提出了两个截然相反事件流概念,是啥呢?我想大家都应该有听过 事件捕获和事件冒泡

事件捕获

直接上图:


image.png

举个例子

<html>
  <body>
    <div>今晚该点我了,小哥!</div>
  </body>
</html>

单击div元素,click将会以以下顺序发生:

  1. document
  2. html
  3. body
  4. div

注意:
1.IE9一下不支持事件捕获;
2.DOM2级规范要求事件从document对象开始传播,但浏览器多数都是从window对象开始传播

事件冒泡

首先,说个重点因为浏览器兼容性问题,早期(IE9之前)是不支持事件捕获的,所以建议使用时间冒泡处理事件

上图


image.png

同样的代码(时间捕获的代码)

事件的顺序刚好相反:

  1. div
  2. body
  3. html
  4. document
DOM事件流

DOM2级事件 规定事件流包括3个阶段

  1. 事件捕获阶段
  2. 目标阶段
  3. 时间冒泡阶段

在DOM事件流中,实际的目标(div)在捕获阶段是不会接收到事件的,这意味着事件从documen->html->body就停止了。在事件处理中,将"处于目标阶段"看做是冒泡阶段的一部分。

但是,多数支持DOM2事件流的现代浏览器都实现了在捕获阶段触发事件对象上的事件,so~

以上是书本原话,大家自行体会。

注意,IE9以下是不支持DOM2级事件流的

事件处理程序

用来响应某个事件的函数叫做事件处理程序(或事件侦听器

为事件指定处理程序的方式有以下几种:

  1. HTML事件处理程序
  2. DOM0级时间处理程序
  3. DOM2级事件处理程序
  4. IE事件处理程序
HTML 事件处理程序

看代码

  • 方法一
<input type='button' value='Click me' onclick='alert(123)' />
  • 方法二
<script>
  function showMessage(){
    console.log(123);
  }
</script>
<input type='button' value='Click me' onclick='showMessage()' />

这两种注册事件的方式,大家应该都不陌生,需要一提的是在方法一中,代码部分(alert(123))是作为JavaScript代码来处理的且是嵌套在html代码中的,如果代码中包含未经过转义的HTMl语法字符是有问题的,所以请转义OR用第二种方法。

代码执行时的作用域问题
  • 在代码执行时以上两种方法都有权访问全局作用域中的任何代码
  • 当前的this指向目标元素

作用域扩展
看实例代码:JSFiddeler代码示例

代码截图


作用域扩展.png

  • 在函数内部,你可以像访问局部变量一样访问document及该元素本身的成员
  • 如果当前元素是一个表单的输入元素,则作用域中还会包含访问表单元素(父元素)的入口,这样可以更快的访问表单字段。
HTML事件处理程序的缺点
  • 时差问题,当事件触发时,事件处理程序可能尚不具备执行条件
    举个例子,前面的showMessage如果在按钮的下方,用户点击按钮时,showMessage还未加载完毕就会出现错误
  • 作用域链可能因为浏览器的的不同产生差异
  • HTML代码和JavaScript代码紧密耦合
DOM0 级时间处理程序

先说优点

  1. 简单
  2. 兼容性非常好,具有跨浏览器的优势

看看如何注册

var btn = document.getElementById('mybtn');
btn.onclick = function(){
  console.log('clicked');
}

嗯,简单不需要多说什么。

几点需要注意的

  • 处理程序中this指向当前元素
  • 该种方式添加的事件处理程序都是在事件流的冒泡阶段被处理的
  • btn.onclick=null时,可以去除事件绑定(有好处,日后展开)
DOM2 级处理程序

DOM2级事件定义了两个方法,用来处理和删除事件处理程序addEventListener()removeEventListener();所有实现DOM2级规范的dom节点都包含这两个方法;这两个函数有三个参数,依次顺序分别是:要处理的事件名称(click,load)、处理函数、以及一个布尔值。最后这个布尔值如果是true表示在捕获阶段调用时间处理程序,否则在冒泡阶段调用。

看代码

var btn = document.getElementById('mybtn');
btn.addEventListener('click',function(){
  console.log(1111);
},true);

如果需要将事件处理程序移除,必须使用有签名的处理函数,上述代码的匿名函数则无法移除`

btn.removeEventListener("click",handler,true)

优点

  • 可以添加多个处理程序
  • 解耦

福利:查看代码 ,可以稍稍理解下这里的捕获阶段调用事件处理程序和冒泡阶段调用是啥意思

IE处理程序

说实话,我个人是不太想说这个的,因为它会让人混乱,我建议还是先了解标准之后再来阅读这个比较好。但为了知识的连贯性,我还是大概说一下下。

IE早期的版本(我试了ie11好像已经去除了,估计还是ie9之前,具体没有找到资料)中实现了类似DOM2中的两个方法attachEventdetachEvent

以下列举这两个方法的不同

  • 因为IE8及更早的版本只支持时间冒泡,so 通过该方法注册的事件处理程序都会被添加到冒泡阶段
  • 看下代码
      btn.attachEvent('onclick',handler)
    
    多了个 on
  • this指向window
  • 注册了的多个处理程序的执行顺序和DOM2顺序相反,DOM2是先注册的先执行

跨浏览器的事件处理程序

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

推荐阅读更多精彩内容