JavaScript — event介绍以及兼容处理

JavaScript — event介绍以及兼容处理

1.事件流

浏览器发展到第四代时(IE4及 Netscape Communicator 4),浏览器开发团队遇到一个问题:页面的哪个部分会拥有某个特定的事件?可以想象在一张纸上的一组同心圆,如果把手指放在圆心上,那么你的手指指向的不是一个圆,而是纸上的所有圆。即在点击一个按钮时,不仅点击了按钮,也点击了整个页面。

事件流描述的是从页面中接收事件的顺序。不过IE 和 Netscape 开发团队提出的想法差不多完全相反。

IE的事件流是事件冒泡流,而 Netscape Communicator 的事件流是事件捕获流。

1.1 事件冒泡

IE的事件流叫做事件冒泡(event bubbling),即事件开始时是由最具体的元素接收,然后逐级向上传播到较为不具体的节点。

备注:所有现代的浏览器都支持事件冒泡,但是在具体实现上还有一些差别。IE5.5 以及更早的版本中的事件冒泡会跳过 html 元素,即从body直接到 document。而IE9、Firefox、Chrome和Safari则将事件一直冒泡到window对象。

1.2 事件捕获

Netscape Communicator 团队提出的另一种事件流叫做事件捕获。思想是不太具体的节点应该更早的接收到事件,而最具体的节点应该最后接收到事件。

事件捕获的用意在于事件到达预定目标之前捕获它。

虽然 事件捕获 是Netscape Communicator 唯一支持的事件流模型,但是IE9、Firefox、Opera、Chrome和Safari目前也都支持这种事件流模型。

尽管“DOM2级事件”规范要求事件应该从document对象开始传播,但是这些浏览器都是从window对象开始捕获事件的。

由于老版本的浏览器不支持,因此很少有人使用事件捕获。

1.3 DOM 事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,这为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出响应。

2. 事件处理程序

2.1 HTML 事件处理程序

如下:

<input type="button" value="click" onclick="alert('hello')" />

2.2 DOM0级事件处理程序

通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代Web浏览器中出现的,而且至今仍然为所有现代浏览器支持。一是简单,二是具有跨浏览器优势。

每个元素都有自己的事件处理程序属性,这些属性通常全部小写,例如:onclick。将这种属性的值设置为一个函数,就可以制定事件处理程序。

如下例:

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(this.id); // "myBtn"
}
btn.onclick = null; // 删除事件处理程序

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

2.3 DOM2级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。都接受三个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。默认是 false。

使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。

var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){alert(this.id)}) // this 指的是元素本身
btn.addEventListener("click",function(){alert("hello word!"))})

通过 addEventListener 添加的事件,只能通过 removeEventListener 移除掉,移除时的参数需要和传入的参数相同。这也意味着传入的匿名参数无法移除。因此尽量避免使用匿名函数。

大多数情况下,都是把事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。万不得已的时候,再添加到捕获阶段。

2.4 IE事件处理程序

IE实现了与DOM中类似的两个方法,attachEvent() 和 detachEvent()。这两个方法接收两个参数,因为只支持冒泡。
与addEventListener 和 removeEventListener 不同的是,接受的第一个参数,必须带on。如单击事件,为"onclick";还有添加多个事件的时候,此方法按照添加的顺序反向执行。

此方法与DOM0级方法的主要区别是在于事件处理程序的作用域。此方法的事件处理程序会在全局作用域中运行,其中的this为window

2.5 跨浏览器的事件处理程序

因为不同浏览器对于事件的处理不一样,所以可以手写一些事件兼容方法。如下:

var EventUtil = {
    // 添加事件处理程序
    addHandler: function(element, type, handler) {
        if (element.addEventListener) { // DOM2级 事件处理程序,this 指向元素本身。按照添加的顺序正向执行
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) { // IE 事件处理程序,this 指向 window。按照添加的顺序反向执行
            element.attachEvent("on" + type, handler);
        } else { // DOM0级 事件处理程序。只能绑定一个事件处理程序
            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.event 为 IE 浏览器的获取方式
    getEvent: function(event) {
        return event ? event : window.event;
    },
    // 获取event的target。 event.srcElement 只对老版本的 IE 浏览器有效
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    // 取消事件的默认行为
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false; // IE
        }
    },
    // 阻止事件冒泡
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true; // IE
        }
    }
}

3.事件对象小记

3.1 非IE浏览器

  1. target 和 currentTarget 意义不同。 currentTarget 指的是处理这个事件的节点;target 指的是 触发事件的实际目标。
  2. preventDefault 可以阻止特定事件的默认行为。如a标签的跳转,form表单的提交,复选框的选中等等。但是只有 cancelable 为true的才可以使用。
  3. stopPropagation 可以阻止事件冒泡。比如 button 和 body都有对click事件的处理程序,如果不作特殊处理,这两个事件处理程序都会执行,而是用stopPropagation则会阻止body中事件的触发;

3.2 IE中事件对象略有不同:

  1. cancelBubble,默认值为false,将其设置为true,可阻止事件冒泡;类比stopPropagation
  2. returnValue,默认值为true,将其设置为false,可以阻止事件的默认行为;类比preventDefault
  3. IE的DOM0级事件,添加事件处理程序的时候,event是作为window的一个属性而存在,即需要通过window.event来获取;
  4. 如果是使用 attachEvent() 的方法添加事件处理程序,会有一个event对象作为参数传递到方法中,同时也可以通过 window.event来获取;
  5. srcElement与DOM中的target属性相同。

备注:事件处理程序的作用域是根据指定他的方式确定的,所以不能认为this始终等于时间目标。还是使用 srcElement 保险。

如下例:

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

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,473评论 1 11
  • JavaScript 程序采用了异步事件驱动编程模型。在这种程序设计风格下,当文档、浏览器、元素或与之相关的对象发...
    劼哥stone阅读 1,251评论 3 11
  • JavaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬...
    threetowns阅读 339评论 0 0
  • js之事件机制 1、事件初探 1.1 js事件的概述 JavaScript事件:JavaScript是基于事件驱动...
    道无虚阅读 2,334评论 1 3
  • 事件流 JavaScript与HTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互...
    DHFE阅读 822评论 0 3